From 6dd81ca9ee913c2b29f30150319fd80bc1fb015b Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Thu, 12 May 2022 17:42:34 -0300 Subject: [PATCH 001/294] implement basehandler contract interface for slack channel handler --- handlers/slack/slack.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 handlers/slack/slack.go diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go new file mode 100644 index 000000000..25643bfb9 --- /dev/null +++ b/handlers/slack/slack.go @@ -0,0 +1,37 @@ +package slack + +import ( + "context" + "net/http" + + "github.com/nyaruka/courier" + "github.com/nyaruka/courier/handlers" +) + +var apiURL = "https://api.slack.com" + +func init() { + courier.RegisterHandler(newHandler()) +} + +type handler struct { + handlers.BaseHandler +} + +func newHandler() courier.ChannelHandler { + return &handler{handlers.NewBaseHandler(courier.ChannelType("SL"), "Slack")} +} + +func (h *handler) Initialize(s courier.Server) error { + h.SetServer(s) + s.AddHandlerRoute(h, http.MethodPost, "receive", h.receiveMessage) + return nil +} + +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { + return nil, nil +} + +func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { + return nil, nil +} From 8d51c6a4ea5982d99a91564809aa37c084f2624a Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Thu, 12 May 2022 17:43:43 -0300 Subject: [PATCH 002/294] setup initial slack channel tests --- handlers/slack/slack_test.go | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 handlers/slack/slack_test.go diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go new file mode 100644 index 000000000..ca50bf948 --- /dev/null +++ b/handlers/slack/slack_test.go @@ -0,0 +1,40 @@ +package slack + +import ( + "net/http/httptest" + "testing" + + "github.com/nyaruka/courier" + . "github.com/nyaruka/courier/handlers" +) + +var testChannels = []courier.Channel{ + courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SL", "2022", "US", map[string]interface{}{"auth_token": "abc123"}), +} + +var helloMsg = `{ + +}` + +func setSendUrl(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { + apiURL = s.URL +} + +var defaultSendTestCases = []ChannelSendTestCase{ + { + Label: "Plain Send", + Text: "Simple Message", URN: "slack:12345", + Status: "W", ExternalID: "123", + ResponseBody: `{}`, + ResponseStatus: 200, + PostParams: map[string]string{}, + SendPrep: setSendUrl, + }, +} + +func TestSending(t *testing.T) { + var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SL", "2022", "US", + map[string]interface{}{courier.ConfigAuthToken: "auth_token"}) + + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) +} From 39143718a4b7e88d42d83c405af9b570cf6254f2 Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Thu, 12 May 2022 18:57:37 -0300 Subject: [PATCH 003/294] add inital slack moplayload and config token --- handlers/slack/slack.go | 16 +++++++++++++++- handlers/slack/slack_test.go | 9 ++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index 25643bfb9..e4fd79c5f 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -2,13 +2,18 @@ package slack import ( "context" + "fmt" "net/http" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" ) -var apiURL = "https://api.slack.com" +var apiURL = "https://slack.com/api/" + +const ( + configBotToken = "bot_token" +) func init() { courier.RegisterHandler(newHandler()) @@ -33,5 +38,14 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { + botToken := msg.Channel().StringConfigForKey(configBotToken, "") + if botToken == "" { + return nil, fmt.Errorf("missing bot token for SL channel") + } return nil, nil } + +type moPayload struct { + Channel string `json:"channel"` + Text string `json:"text"` +} diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index ca50bf948..f9abae1a1 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -25,16 +25,19 @@ var defaultSendTestCases = []ChannelSendTestCase{ Label: "Plain Send", Text: "Simple Message", URN: "slack:12345", Status: "W", ExternalID: "123", - ResponseBody: `{}`, + ResponseBody: `{"ok":true,"channel":"C0123ABCDEF","ts":"1652391855.466329","message":{"bot_id":"B03F2F82B4N","type":"message","text":"hello","user":"U03F94B4UMQ","ts":"1652391855.466329","app_id":"A03FBEC4NE8","team":"T03CN5KTA6S","bot_profile":{"id":"B03F2F82B4N","app_id":"A03FBEC4NE8","name":"Test Bot","icons":{"image_36":"https:\/\/a.slack-edge.com\/80588\/img\/plugins\/app\/bot_36.png","image_48":"https:\/\/a.slack-edge.com\/80588\/img\/plugins\/app\/bot_48.png","image_72":"https:\/\/a.slack-edge.com\/80588\/img\/plugins\/app\/service_72.png"},"deleted":false,"updated":1652389333,"team_id":"T03CN5KTA6S"},"blocks":[{"type":"rich_text","block_id":"jv9h","elements":[{"type":"rich_text_section","elements":[{"type":"text","text":"hello"}]}]}]}}`, ResponseStatus: 200, - PostParams: map[string]string{}, + RequestBody: `{"chanel": "C0123ABCDEF", "text": "Hello"}`, SendPrep: setSendUrl, }, } func TestSending(t *testing.T) { var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SL", "2022", "US", - map[string]interface{}{courier.ConfigAuthToken: "auth_token"}) + map[string]interface{}{ + courier.ConfigAuthToken: "xoxb-123456789...", + }, + ) RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) } From 264a678342eb54bae744713898171c8c1604df89 Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Fri, 13 May 2022 12:43:11 -0300 Subject: [PATCH 004/294] slack channel send text message done --- handlers/slack/slack.go | 44 ++++++++++++++++++++++++++++++++---- handlers/slack/slack_test.go | 28 +++++++++++++++++++---- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index e4fd79c5f..ebdd41382 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -1,15 +1,19 @@ package slack import ( + "bytes" "context" + "encoding/json" "fmt" "net/http" + "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/utils" ) -var apiURL = "https://slack.com/api/" +var apiURL = "https://slack.com/api" const ( configBotToken = "bot_token" @@ -40,12 +44,44 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { botToken := msg.Channel().StringConfigForKey(configBotToken, "") if botToken == "" { - return nil, fmt.Errorf("missing bot token for SL channel") + return nil, fmt.Errorf("missing bot token for SL/slack channel") } - return nil, nil + sendURL := apiURL + "/chat.postMessage" + + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + msgPayload := &mtPayload{ + Channel: msg.URN().Path(), + Text: msg.Text(), + } + + body, err := json.Marshal(msgPayload) + if err != nil { + return status, err + } + + req, err := http.NewRequest(http.MethodPost, sendURL, bytes.NewReader(body)) + if err != nil { + return status, err + } + req.Header.Set("Content-Type", "application/json; charset=utf-8") + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", botToken)) + + rr, err := utils.MakeHTTPRequest(req) + + log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + status.AddLog(log) + + ok, err := jsonparser.GetBoolean([]byte(rr.Body), "ok") + if err != nil || !ok { + return status, err + } + + status.SetStatus(courier.MsgWired) + + return status, nil } -type moPayload struct { +type mtPayload struct { Channel string `json:"channel"` Text string `json:"text"` } diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index f9abae1a1..0548bdf01 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -23,11 +23,29 @@ func setSendUrl(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ { Label: "Plain Send", - Text: "Simple Message", URN: "slack:12345", - Status: "W", ExternalID: "123", - ResponseBody: `{"ok":true,"channel":"C0123ABCDEF","ts":"1652391855.466329","message":{"bot_id":"B03F2F82B4N","type":"message","text":"hello","user":"U03F94B4UMQ","ts":"1652391855.466329","app_id":"A03FBEC4NE8","team":"T03CN5KTA6S","bot_profile":{"id":"B03F2F82B4N","app_id":"A03FBEC4NE8","name":"Test Bot","icons":{"image_36":"https:\/\/a.slack-edge.com\/80588\/img\/plugins\/app\/bot_36.png","image_48":"https:\/\/a.slack-edge.com\/80588\/img\/plugins\/app\/bot_48.png","image_72":"https:\/\/a.slack-edge.com\/80588\/img\/plugins\/app\/service_72.png"},"deleted":false,"updated":1652389333,"team_id":"T03CN5KTA6S"},"blocks":[{"type":"rich_text","block_id":"jv9h","elements":[{"type":"rich_text_section","elements":[{"type":"text","text":"hello"}]}]}]}}`, + Text: "Simple Message", URN: "slack:C0123ABCDEF", + Status: "W", + ResponseBody: `{"ok":true,"channel":"C0123ABCDEF"}`, ResponseStatus: 200, - RequestBody: `{"chanel": "C0123ABCDEF", "text": "Hello"}`, + RequestBody: `{"channel":"C0123ABCDEF","text":"Simple Message"}`, + SendPrep: setSendUrl, + }, + { + Label: "Unicode Send", + Text: "☺", URN: "slack:U0123ABCDEF", + Status: "W", + ResponseBody: `{"ok":true,"channel":"U0123ABCDEF"}`, + ResponseStatus: 200, + RequestBody: `{"channel":"U0123ABCDEF","text":"☺"}`, + SendPrep: setSendUrl, + }, + { + Label: "Send Text Error", + Text: "Hello", URN: "slack:U0123ABCDEF", + Status: "E", + ResponseBody: `{"ok":false,"error":"invalid_auth"}`, + ResponseStatus: 200, + RequestBody: `{"channel":"U0123ABCDEF","text":"Hello"}`, SendPrep: setSendUrl, }, } @@ -35,7 +53,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SL", "2022", "US", map[string]interface{}{ - courier.ConfigAuthToken: "xoxb-123456789...", + configBotToken: "xoxb-123456789...", }, ) From 08bb918a97ea1a955806d6348758ffdad82c0b1b Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Mon, 23 May 2022 15:08:56 -0300 Subject: [PATCH 005/294] handle verification --- handlers/slack/slack.go | 81 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 3 deletions(-) diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index ebdd41382..5a8dff7d1 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -6,17 +6,21 @@ import ( "encoding/json" "fmt" "net/http" + "strings" + "time" "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/utils" + "github.com/nyaruka/gocommon/urns" ) var apiURL = "https://slack.com/api" const ( - configBotToken = "bot_token" + configBotToken = "bot_token" + configValidationToken = "verification_token" ) func init() { @@ -33,14 +37,51 @@ func newHandler() courier.ChannelHandler { func (h *handler) Initialize(s courier.Server) error { h.SetServer(s) - s.AddHandlerRoute(h, http.MethodPost, "receive", h.receiveMessage) + s.AddHandlerRoute(h, http.MethodPost, "receive", h.receiveEvent) return nil } -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func handleURLVerification(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, payload *moPayload) ([]courier.Event, error) { + validationToken := channel.ConfigForKey(configValidationToken, "") + if validationToken != payload.Token { + w.WriteHeader(http.StatusForbidden) + return nil, fmt.Errorf("Wrong validation token for channel: %s", channel.UUID()) + } + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusOK) + w.Write([]byte(payload.Challenge)) return nil, nil } +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { + payload := &moPayload{} + err := handlers.DecodeAndValidateJSON(payload, r) + if err != nil { + return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) + } + + if payload.Type == "url_verification" { + return handleURLVerification(ctx, channel, w, r, payload) + } + + date := time.Unix(int64(payload.EventTime), 0) + + urn := urns.URN(fmt.Sprintf("%s:%s", "slack", payload.Event.User)) + // urn, err := urns.NewURNFromParts("slack", payload.Event.User, "", "") + // if err != nil { + // return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) + // } + + if strings.Contains(payload.Event.Type, "message") { + text := payload.Event.Text + + msg := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date).WithExternalID(payload.EventID).WithContactName("") + + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + } + return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "Ignoring request, no message") +} + func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { botToken := msg.Channel().StringConfigForKey(configBotToken, "") if botToken == "" { @@ -85,3 +126,37 @@ type mtPayload struct { Channel string `json:"channel"` Text string `json:"text"` } + +type moPayload struct { + Token string `json:"token,omitempty"` + TeamID string `json:"team_id,omitempty"` + APIAppID string `json:"api_app_id,omitempty"` + Event struct { + Type string `json:"type,omitempty"` + Channel string `json:"channel,omitempty"` + User string `json:"user,omitempty"` + Text string `json:"text,omitempty"` + Ts string `json:"ts,omitempty"` + EventTs string `json:"event_ts,omitempty"` + ChannelType string `json:"channel_type,omitempty"` + } `json:"event,omitempty"` + Type string `json:"type,omitempty"` + AuthedUsers []string `json:"authed_users,omitempty"` + AuthedTeams []string `json:"authed_teams,omitempty"` + Authorizations []struct { + EnterpriseID string `json:"enterprise_id,omitempty"` + TeamID string `json:"team_id,omitempty"` + UserID string `json:"user_id,omitempty"` + IsBot bool `json:"is_bot,omitempty"` + } `json:"authorizations,omitempty"` + EventContext string `json:"event_context,omitempty"` + EventID string `json:"event_id,omitempty"` + EventTime int `json:"event_time,omitempty"` + Challenge string `json:"challenge,omitempty"` +} + +type item struct { + Type string `json:"type,omitempty"` + Channel string `json:"channel,omitempty"` + Ts string `json:"ts,omitempty"` +} From e8b18e9047b9a4ca46040f34fad1b397ba402f95 Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Mon, 23 May 2022 15:09:27 -0300 Subject: [PATCH 006/294] test verification and receiveEvent --- handlers/slack/slack_test.go | 66 +++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 9 deletions(-) diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 0548bdf01..705a90225 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -8,18 +8,54 @@ import ( . "github.com/nyaruka/courier/handlers" ) +const ( + channelUUID = "8eb23e93-5ecb-45ba-b726-3b064e0c568c" + receiveURL = "/c/sl/" + channelUUID + "/receive/" +) + var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SL", "2022", "US", map[string]interface{}{"auth_token": "abc123"}), + courier.NewMockChannel(channelUUID, "SL", "2022", "US", map[string]interface{}{"bot_token": "xoxb-abc123"}), } -var helloMsg = `{ - +const helloMsg = `{ + "token": "one-long-verification-token", + "team_id": "T061EG9R6", + "api_app_id": "A0PNCHHK2", + "event": { + "type": "message", + "channel": "C0123ABCDEF", + "user": "U0123ABCDEF", + "text": "Hello World!", + "ts": "1355517523.000005", + "event_ts": "1355517523.000005", + "channel_type": "channel" + }, + "type": "event_callback", + "authed_teams": [ + "T061EG9R6" + ], + "event_id": "Ev0PV52K21", + "event_time": 1355517523 }` func setSendUrl(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { apiURL = s.URL } +var testCases = []ChannelHandleTestCase{ + { + Label: "Receive Hello Msg", + URL: receiveURL, + Headers: map[string]string{}, + Data: helloMsg, + URN: Sp("slack:U0123ABCDEF"), + Text: Sp("Hello World!"), + Status: 200, + Response: "Accepted", + ExternalID: Sp("Ev0PV52K21"), + }, +} + var defaultSendTestCases = []ChannelSendTestCase{ { Label: "Plain Send", @@ -50,12 +86,24 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, } +func TestHandler(t *testing.T) { + RunChannelTestCases(t, testChannels, newHandler(), testCases) +} + func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SL", "2022", "US", - map[string]interface{}{ - configBotToken: "xoxb-123456789...", - }, - ) + RunChannelSendTestCases(t, testChannels[0], newHandler(), defaultSendTestCases, nil) +} - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) +func TestVerification(t *testing.T) { + RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ + {Label: "Valid token", URL: receiveURL, Status: 200, + Data: `{"token":"xoxb-abc123","challenge":"challenge123","type":"url_verification"}`, + Headers: map[string]string{"content-type": "text/plain"}, + Response: "challenge123", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + }, + {Label: "Invalid token", URL: receiveURL, Status: 403, + Data: `{"token":"abc321","challenge":"challenge123","type":"url_verification"}`, + Headers: map[string]string{"content-type": "text/plain"}, + }, + }) } From 87b235beb44e3b93484e7f42bd3ab937d42a88b2 Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Tue, 24 May 2022 15:06:42 -0300 Subject: [PATCH 007/294] slack channel receive file support --- handlers/slack/slack.go | 102 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index 5a8dff7d1..9b8fd8185 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -14,12 +14,14 @@ import ( "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" + "github.com/pkg/errors" ) var apiURL = "https://slack.com/api" const ( configBotToken = "bot_token" + configUserToken = "user_token" configValidationToken = "verification_token" ) @@ -73,15 +75,70 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h // } if strings.Contains(payload.Event.Type, "message") { - text := payload.Event.Text + attachmentURLs := make([]string, 0) + for _, file := range payload.Event.Files { + fileURL, err := h.resolveFile(ctx, channel, file) + if err != nil { + courier.LogRequestError(r, channel, err) + } else { + attachmentURLs = append(attachmentURLs, fileURL) + } + } + text := payload.Event.Text msg := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date).WithExternalID(payload.EventID).WithContactName("") + for _, attURL := range attachmentURLs { + msg.WithAttachment(attURL) + } + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) } return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "Ignoring request, no message") } +func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file file) (string, error) { + userToken := channel.StringConfigForKey(configUserToken, "") + + fileApiURL := apiURL + "/files.sharedPublicURL" + + data := strings.NewReader(fmt.Sprintf(`{"file":"%s"}`, file.ID)) + req, err := http.NewRequest(http.MethodPost, fileApiURL, data) + if err != nil { + courier.LogRequestError(req, channel, err) + return "", err + } + req.Header.Add("Content-Type", "application/json; charset=utf-8") + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", userToken)) + + rr, err := utils.MakeHTTPRequest(req) + if err != nil { + log := courier.NewChannelLogFromRR("File Resolving", channel, courier.NilMsgID, rr).WithError("File Resolving Error", err) + h.Backend().WriteChannelLogs(ctx, []*courier.ChannelLog{log}) + return "", err + } + + var fResponse fileResponse + if err := json.Unmarshal([]byte(rr.Body), &fResponse); err != nil { + return "", errors.Errorf("couldn't unmarshal file response: %v", err) + } + + currentFile := fResponse.File + + if !fResponse.OK { + if fResponse.Error != "already_public" { + return "", errors.Errorf("couldn't resolve file for file id: %s. %s", file.ID, fResponse.Error) + } + currentFile = file + } + + pubLnkSplited := strings.Split(currentFile.PermalinkPublic, "-") + pubSecret := pubLnkSplited[len(pubLnkSplited)-1] + filePath := currentFile.URLPrivate + "?pub_secret=" + pubSecret + + return filePath, nil +} + func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { botToken := msg.Channel().StringConfigForKey(configBotToken, "") if botToken == "" { @@ -139,6 +196,7 @@ type moPayload struct { Ts string `json:"ts,omitempty"` EventTs string `json:"event_ts,omitempty"` ChannelType string `json:"channel_type,omitempty"` + Files []file `json:"files"` } `json:"event,omitempty"` Type string `json:"type,omitempty"` AuthedUsers []string `json:"authed_users,omitempty"` @@ -160,3 +218,45 @@ type item struct { Channel string `json:"channel,omitempty"` Ts string `json:"ts,omitempty"` } + +type file struct { + ID string `json:"id"` + Created int `json:"created"` + Timestamp int `json:"timestamp"` + Name string `json:"name"` + Title string `json:"title"` + Mimetype string `json:"mimetype"` + Filetype string `json:"filetype"` + PrettyType string `json:"pretty_type"` + User string `json:"user"` + Editable bool `json:"editable"` + Size int `json:"size"` + Mode string `json:"mode"` + IsExternal bool `json:"is_external"` + ExternalType string `json:"external_type"` + IsPublic bool `json:"is_public"` + PublicURLShared bool `json:"public_url_shared"` + DisplayAsBot bool `json:"display_as_bot"` + Username string `json:"username"` + URLPrivate string `json:"url_private"` + URLPrivateDownload string `json:"url_private_download"` + MediaDisplayType string `json:"media_display_type"` + Thumb64 string `json:"thumb_64"` + Thumb80 string `json:"thumb_80"` + Thumb360 string `json:"thumb_360"` + Thumb360W int `json:"thumb_360_w"` + Thumb360H int `json:"thumb_360_h"` + Thumb160 string `json:"thumb_160"` + OriginalW int `json:"original_w"` + OriginalH int `json:"original_h"` + ThumbTiny string `json:"thumb_tiny"` + Permalink string `json:"permalink"` + PermalinkPublic string `json:"permalink_public"` + HasRichPreview bool `json:"has_rich_preview"` +} + +type fileResponse struct { + OK bool `json:"ok"` + File file `json:"file"` + Error string `json:"error"` +} From 53361bf7df744b1e8706a546d27d671f506b817d Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Tue, 24 May 2022 19:24:46 -0300 Subject: [PATCH 008/294] test slack channel handler receive file msg --- handlers/slack/slack.go | 36 +++-- handlers/slack/slack_test.go | 297 +++++++++++++++++++++++++++++++++++ 2 files changed, 319 insertions(+), 14 deletions(-) diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index 9b8fd8185..c42ab8784 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -25,6 +25,11 @@ const ( configValidationToken = "verification_token" ) +var ( + ErrAlreadyPublic = "already_public" + ErrPublicVideoNotAllowed = "public_video_not_allowed" +) + func init() { courier.RegisterHandler(newHandler()) } @@ -97,7 +102,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "Ignoring request, no message") } -func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file file) (string, error) { +func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file moFile) (string, error) { userToken := channel.StringConfigForKey(configUserToken, "") fileApiURL := apiURL + "/files.sharedPublicURL" @@ -126,15 +131,18 @@ func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file currentFile := fResponse.File if !fResponse.OK { - if fResponse.Error != "already_public" { - return "", errors.Errorf("couldn't resolve file for file id: %s. %s", file.ID, fResponse.Error) + if fResponse.Error != ErrAlreadyPublic { + if fResponse.Error == ErrPublicVideoNotAllowed { + return "", errors.Errorf("public sharing of videos is not available for a free instance of Slack. file id: %s. error: %s", file.ID, fResponse.Error) + } + return "", errors.Errorf("couldn't resolve file for file id: %s. error: %s", file.ID, fResponse.Error) } currentFile = file } pubLnkSplited := strings.Split(currentFile.PermalinkPublic, "-") pubSecret := pubLnkSplited[len(pubLnkSplited)-1] - filePath := currentFile.URLPrivate + "?pub_secret=" + pubSecret + filePath := currentFile.URLPrivateDownload + "?pub_secret=" + pubSecret return filePath, nil } @@ -189,14 +197,14 @@ type moPayload struct { TeamID string `json:"team_id,omitempty"` APIAppID string `json:"api_app_id,omitempty"` Event struct { - Type string `json:"type,omitempty"` - Channel string `json:"channel,omitempty"` - User string `json:"user,omitempty"` - Text string `json:"text,omitempty"` - Ts string `json:"ts,omitempty"` - EventTs string `json:"event_ts,omitempty"` - ChannelType string `json:"channel_type,omitempty"` - Files []file `json:"files"` + Type string `json:"type,omitempty"` + Channel string `json:"channel,omitempty"` + User string `json:"user,omitempty"` + Text string `json:"text,omitempty"` + Ts string `json:"ts,omitempty"` + EventTs string `json:"event_ts,omitempty"` + ChannelType string `json:"channel_type,omitempty"` + Files []moFile `json:"files"` } `json:"event,omitempty"` Type string `json:"type,omitempty"` AuthedUsers []string `json:"authed_users,omitempty"` @@ -219,7 +227,7 @@ type item struct { Ts string `json:"ts,omitempty"` } -type file struct { +type moFile struct { ID string `json:"id"` Created int `json:"created"` Timestamp int `json:"timestamp"` @@ -257,6 +265,6 @@ type file struct { type fileResponse struct { OK bool `json:"ok"` - File file `json:"file"` + File moFile `json:"file"` Error string `json:"error"` } diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 705a90225..61c28c229 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -1,9 +1,14 @@ package slack import ( + "encoding/json" + "io" + "log" + "net/http" "net/http/httptest" "testing" + "github.com/buger/jsonparser" "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" ) @@ -38,6 +43,215 @@ const helloMsg = `{ "event_time": 1355517523 }` +const imageFileMsg = `{ + "token": "Bwf82iq5kCEkHOzRQ7p4FqkQ", + "team_id": "T03CN5KTA6S", + "api_app_id": "A03FTC8MZ63", + "event": { + "type": "message", + "text": "", + "files": [ + { + "id": "F03GTH43SSF", + "created": 1653417049, + "timestamp": 1653417049, + "name": "batata.jpg", + "title": "batata.jpg", + "mimetype": "image/jpeg", + "filetype": "jpg", + "pretty_type": "JPEG", + "user": "U0123ABCDEF", + "editable": false, + "size": 7130, + "mode": "hosted", + "is_external": false, + "external_type": "", + "is_public": true, + "public_url_shared": false, + "display_as_bot": false, + "username": "", + "url_private": "https://files.slack.com/files-pri/T03CN5KTA6S-F03GTH43SSF/batata.jpg", + "url_private_download": "https://files.slack.com/files-pri/T03CN5KTA6S-F03GTH43SSF/download/batata.jpg", + "media_display_type": "unknown", + "thumb_64": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GTH43SSF-75138e6784/batata_64.jpg", + "thumb_80": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GTH43SSF-75138e6784/batata_80.jpg", + "thumb_360": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GTH43SSF-75138e6784/batata_360.jpg", + "thumb_360_w": 360, + "thumb_360_h": 360, + "thumb_160": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GTH43SSF-75138e6784/batata_160.jpg", + "original_w": 400, + "original_h": 400, + "thumb_tiny": "AwAwADDTooooAKKY7Y4HWmjnqalysOxLRTUJJxTqadxBTS4HvRIcLURIFTKVhpDZJhu6UAse1IuCSR16U/NZPXUvYWNyOq81MDkZFQk9xT4+5rSL6EseRkYNRtCD0JFSUVbSZJWW3dGzvz7YpTuB5VvwFWKKTgh3IQpYdxUoGBS0U0rA2f/Z", + "permalink": "https://teste-apigrupo.slack.com/files/U0123ABCDEF/F03GTH43SSF/batata.jpg", + "permalink_public": "https://slack-files.com/T03CN5KTA6S-F03GTH43SSF-39fcf577f2", + "has_rich_preview": false + } + ], + "upload": false, + "user": "U0123ABCDEF", + "display_as_bot": false, + "ts": "1653417052.881009", + "client_msg_id": "0e400b8f-07c4-452f-a13e-2744fcae2558", + "channel": "C03CUQQBHEF", + "subtype": "file_share", + "event_ts": "1653417052.881009", + "channel_type": "channel" + }, + "type": "event_callback", + "event_id": "Ev0PV52K21", + "event_time": 1653417052, + "authorizations": [ + { + "enterprise_id": null, + "team_id": "T03CN5KTA6S", + "user_id": "U03G81FQM98", + "is_bot": true, + "is_enterprise_install": false + } + ], + "is_ext_shared_channel": false, + "event_context": "4-eyJldCI6Im1lc3NhZ2UiLCJ0aWQiOiJUMDNDTjVLVEE2UyIsImFpZCI6IkEwM0ZUQzhNWjYzIiwiY2lkIjoiQzAzQ1VRUUJIRUYifQ" +} +` + +const audioFileMsg = `{ + "token": "Bwf82iq5kCEkHOzRQ7p4FqkQ", + "team_id": "T03CN5KTA6S", + "api_app_id": "A03FTC8MZ63", + "event": { + "type": "message", + "text": "", + "files": [ + { + "id": "F03GWURCZL4", + "created": 1653428828, + "timestamp": 1653428828, + "name": "here we go again.mp3", + "title": "here we go again.mp3", + "mimetype": "audio/mpeg", + "filetype": "mp3", + "pretty_type": "MP3", + "user": "U0123ABCDEF", + "editable": false, + "size": 102122, + "mode": "hosted", + "is_external": false, + "external_type": "", + "is_public": true, + "public_url_shared": false, + "display_as_bot": false, + "username": "", + "transcription": { + "status": "none" + }, + "url_private": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GWURCZL4-9aaa1171c6/here_we_go_again_audio.mp4", + "url_private_download": "https://files.slack.com/files-pri/T03CN5KTA6S-F03GWURCZL4/download/here_we_go_again.mp3", + "duration_ms": 3187, + "aac": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GWURCZL4-9aaa1171c6/here_we_go_again_audio.mp4", + "audio_wave_samples": [0,0,0,3,5,2,3,6,9,10,9,8,5,3,9,19,22,23,24,25,25,30,28,13,10,10,8,7,4,1,5,7,9,10,9,12,56,35,59,15,10,10,8,6,3,3,6,8,10,10,8,5,2,3,6,8,10,10,22,50,42,20,59,73,30,14,26,67,65,72,72,86,94,36,12,42,100,91,91,86,54,40,23,15,7,5,8,9,10,8,6,3,2,5,8,10,9,8,5,2], + "media_display_type": "audio", + "permalink": "https://teste-apigrupo.slack.com/files/U0123ABCDEF/F03GWURCZL4/here_we_go_again.mp3", + "permalink_public": "https://slack-files.com/T03CN5KTA6S-F03GWURCZL4-471020b300", + "has_rich_preview": false + } + ], + "upload": false, + "user": "U0123ABCDEF", + "display_as_bot": false, + "ts": "1653428835.192419", + "client_msg_id": "c827a681-2641-44ed-8cd5-854339499a1e", + "channel": "C03CUQQBHEF", + "subtype": "file_share", + "event_ts": "1653428835.192419", + "channel_type": "channel" + }, + "type": "event_callback", + "event_id": "Ev0PV52K21", + "event_time": 1653428835, + "authorizations": [ + { + "enterprise_id": null, + "team_id": "T03CN5KTA6S", + "user_id": "U03G81FQM98", + "is_bot": true, + "is_enterprise_install": false + } + ], + "is_ext_shared_channel": false, + "event_context": "4-eyJldCI6Im1lc3NhZ2UiLCJ0aWQiOiJUMDNDTjVLVEE2UyIsImFpZCI6IkEwM0ZUQzhNWjYzIiwiY2lkIjoiQzAzQ1VRUUJIRUYifQ" +} +` + +const videoFileMsg = `{ + "token": "Bwf82iq5kCEkHOzRQ7p4FqkQ", + "team_id": "T03CN5KTA6S", + "api_app_id": "A03FTC8MZ63", + "event": { + "type": "message", + "text": "", + "files": [ + { + "id": "F03GDSSMC79", + "created": 1653427226, + "timestamp": 1653427226, + "name": "Walk Cycle Animation sample.mp4", + "title": "Walk Cycle Animation sample.mp4", + "mimetype": "video/mp4", + "filetype": "mp4", + "pretty_type": "MPEG 4 Video", + "user": "U0123ABCDEF", + "editable": false, + "size": 767148, + "mode": "hosted", + "is_external": false, + "external_type": "", + "is_public": true, + "public_url_shared": false, + "display_as_bot": false, + "username": "", + "transcription": { + "status": "none" + }, + "mp4": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GDSSMC79-0af57254d8/walk_cycle_animation_sample.mp4", + "url_private": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GDSSMC79-0af57254d8/walk_cycle_animation_sample.mp4", + "url_private_download": "https://files.slack.com/files-pri/T03CN5KTA6S-F03GDSSMC79/download/walk_cycle_animation_sample.mp4", + "hls": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GDSSMC79-0af57254d8/file.m3u8", + "duration_ms": 19953, + "media_display_type": "video", + "thumb_video": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GDSSMC79-0af57254d8/walk_cycle_animation_sample_thumb_video.jpeg", + "thumb_video_w": 640, + "thumb_video_h": 360, + "permalink": "https://teste-apigrupo.slack.com/files/U0123ABCDEF/F03GDSSMC79/walk_cycle_animation_sample.mp4", + "permalink_public": "https://slack-files.com/T03CN5KTA6S-F03GDSSMC79-805aa1d85f", + "has_rich_preview": false + } + ], + "upload": false, + "user": "U0123ABCDEF", + "display_as_bot": false, + "ts": "1653427243.620839", + "client_msg_id": "72df394d-bfbb-4d90-8db4-cbe5caa76b28", + "channel": "C03CUQQBHEF", + "subtype": "file_share", + "event_ts": "1653427243.620839", + "channel_type": "channel" + }, + "type": "event_callback", + "event_id": "Ev0PV52K21", + "event_time": 1653427243, + "authorizations": [ + { + "enterprise_id": null, + "team_id": "T03CN5KTA6S", + "user_id": "U03G81FQM98", + "is_bot": true, + "is_enterprise_install": false + } + ], + "is_ext_shared_channel": false, + "event_context": "4-eyJldCI6Im1lc3NhZ2UiLCJ0aWQiOiJUMDNDTjVLVEE2UyIsImFpZCI6IkEwM0ZUQzhNWjYzIiwiY2lkIjoiQzAzQ1VRUUJIRUYifQ" +}` + func setSendUrl(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { apiURL = s.URL } @@ -54,6 +268,42 @@ var testCases = []ChannelHandleTestCase{ Response: "Accepted", ExternalID: Sp("Ev0PV52K21"), }, + { + Label: "Receive image file", + URL: receiveURL, + Headers: map[string]string{}, + Data: imageFileMsg, + Attachment: Sp("https://files.slack.com/files-pri/T03CN5KTA6S-F03GTH43SSF/download/batata.jpg?pub_secret=39fcf577f2"), + URN: Sp("slack:U0123ABCDEF"), + Text: Sp(""), + Status: 200, + Response: "Accepted", + ExternalID: Sp("Ev0PV52K21"), + }, + { + Label: "Receive audio file", + URL: receiveURL, + Headers: map[string]string{}, + Data: audioFileMsg, + Attachment: Sp("https://files.slack.com/files-pri/T03CN5KTA6S-F03GWURCZL4/download/here_we_go_again.mp3?pub_secret=471020b300"), + URN: Sp("slack:U0123ABCDEF"), + Text: Sp(""), + Status: 200, + Response: "Accepted", + ExternalID: Sp("Ev0PV52K21"), + }, + { + Label: "Receive video file (not allowed,)", + URL: receiveURL, + Headers: map[string]string{}, + Data: videoFileMsg, + Attachment: nil, + URN: Sp("slack:U0123ABCDEF"), + Text: Sp(""), + Status: 200, + Response: "Accepted", + ExternalID: Sp("Ev0PV52K21"), + }, } var defaultSendTestCases = []ChannelSendTestCase{ @@ -87,6 +337,9 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestHandler(t *testing.T) { + slackServiceMock := buildMockSlackService(testCases) + defer slackServiceMock.Close() + RunChannelTestCases(t, testChannels, newHandler(), testCases) } @@ -107,3 +360,47 @@ func TestVerification(t *testing.T) { }, }) } + +func buildMockSlackService(testCases []ChannelHandleTestCase) *httptest.Server { + + files := make(map[string]moFile) + + for _, tc := range testCases { + var mp moPayload + if err := json.Unmarshal([]byte(tc.Data), &mp); err != nil { + continue + } + + for _, f := range mp.Event.Files { + if _, ok := files[f.ID]; ok == false { + files[f.ID] = f + } + } + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + byteBody, err := io.ReadAll(r.Body) + f, err := jsonparser.GetString(byteBody, "file") + if err != nil { + log.Fatal(err) + } + defer r.Body.Close() + + file, ok := files[f] + + if file.Mimetype == "video/mp4" { + w.Write([]byte(`{"ok":"false","error":"public_video_not_allowed"}`)) + return + } + + if !ok { + w.Write([]byte(`{"ok": "false", "error": "file not found"}`)) + return + } + json.NewEncoder(w).Encode(fileResponse{OK: true, Error: "", File: file}) + })) + + apiURL = server.URL + + return server +} From e3347fbeca8775ccf87c4510956d028277c38930 Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Tue, 24 May 2022 19:58:52 -0300 Subject: [PATCH 009/294] slack channel test verification with proper verification token --- handlers/slack/slack_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 61c28c229..917fede65 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -19,7 +19,7 @@ const ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel(channelUUID, "SL", "2022", "US", map[string]interface{}{"bot_token": "xoxb-abc123"}), + courier.NewMockChannel(channelUUID, "SL", "2022", "US", map[string]interface{}{"bot_token": "xoxb-abc123", "verification_token": "one-long-verification-token"}), } const helloMsg = `{ @@ -350,7 +350,7 @@ func TestSending(t *testing.T) { func TestVerification(t *testing.T) { RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ {Label: "Valid token", URL: receiveURL, Status: 200, - Data: `{"token":"xoxb-abc123","challenge":"challenge123","type":"url_verification"}`, + Data: `{"token":"one-long-verification-token","challenge":"challenge123","type":"url_verification"}`, Headers: map[string]string{"content-type": "text/plain"}, Response: "challenge123", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, }, From 8be26d752b24a1d06bd4f6b2fccd40b7ef4bbec4 Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Tue, 7 Jun 2022 17:02:15 -0300 Subject: [PATCH 010/294] replace gocommon with slack scheme and refactor receive message to receive from channel or direct message --- cmd/courier/main.go | 1 + go.mod | 2 + go.sum | 4 ++ handlers/slack/slack.go | 125 ++++++++++++++++++++++++++++------- handlers/slack/slack_test.go | 18 ++--- 5 files changed, 116 insertions(+), 34 deletions(-) diff --git a/cmd/courier/main.go b/cmd/courier/main.go index 5c44ef92f..3ed69adb7 100644 --- a/cmd/courier/main.go +++ b/cmd/courier/main.go @@ -52,6 +52,7 @@ import ( _ "github.com/nyaruka/courier/handlers/redrabbit" _ "github.com/nyaruka/courier/handlers/rocketchat" _ "github.com/nyaruka/courier/handlers/shaqodoon" + _ "github.com/nyaruka/courier/handlers/slack" _ "github.com/nyaruka/courier/handlers/smscentral" _ "github.com/nyaruka/courier/handlers/start" _ "github.com/nyaruka/courier/handlers/telegram" diff --git a/go.mod b/go.mod index 9f87fcee1..4f2181609 100644 --- a/go.mod +++ b/go.mod @@ -56,3 +56,5 @@ require ( gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) + +replace github.com/nyaruka/gocommon => github.com/Ilhasoft/gocommon v1.19.1-slack-develop diff --git a/go.sum b/go.sum index 38748ea1a..f7ed14e81 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,7 @@ +github.com/Ilhasoft/gocommon v1.16.2-slack-develop h1:pAd+LMH7BEOFxUIeJ1EGJeaMPbMolHpChHmalvjmQbQ= +github.com/Ilhasoft/gocommon v1.16.2-slack-develop/go.mod h1:pk8L9T79VoKO8OWTiZbtUutFPI3sGGKB5u8nNWDKuGE= +github.com/Ilhasoft/gocommon v1.19.1-slack-develop h1:aDh3PyVeFtqFgA/KVBaI/etVhQZ1pPXWnwQo4fM6R4I= +github.com/Ilhasoft/gocommon v1.19.1-slack-develop/go.mod h1:JrQSLAPo9ezSy1AzsJ1zDr1HW0/eu+aipICJkN/+kpg= github.com/antchfx/xmlquery v0.0.0-20181223105952-355641961c92 h1:4EgP6xLAdrD/TRlbSw4n2W6h68K2P3+R7lKqFoL5U9Q= github.com/antchfx/xmlquery v0.0.0-20181223105952-355641961c92/go.mod h1:/+CnyD/DzHRnv2eRxrVbieRU/FIF6N0C+7oTtyUtCKk= github.com/antchfx/xpath v0.0.0-20181208024549-4bbdf6db12aa h1:lL66YnJWy1tHlhjSx8fXnpgmv8kQVYnI4ilbYpNB6Zs= diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index c42ab8784..32cfb5638 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -71,15 +71,29 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return handleURLVerification(ctx, channel, w, r, payload) } - date := time.Unix(int64(payload.EventTime), 0) + // if event is not a message or is from the bot ignore it + if strings.Contains(payload.Event.Type, "message") && payload.Event.BotID == "" { + + date := time.Unix(int64(payload.EventTime), 0) + + var userName string + var path string + if payload.Event.ChannelType == "channel" { + path = payload.Event.Channel + } else if payload.Event.ChannelType == "im" { + path = payload.Event.User + userInfo, err := h.GetUserInfo(payload.Event.User, channel) + if err != nil { + return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) + } + userName = userInfo.User.RealName + } - urn := urns.URN(fmt.Sprintf("%s:%s", "slack", payload.Event.User)) - // urn, err := urns.NewURNFromParts("slack", payload.Event.User, "", "") - // if err != nil { - // return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) - // } + urn, err := urns.NewURNFromParts(urns.SlackScheme, path, "", userName) + if err != nil { + return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) + } - if strings.Contains(payload.Event.Type, "message") { attachmentURLs := make([]string, 0) for _, file := range payload.Event.Files { fileURL, err := h.resolveFile(ctx, channel, file) @@ -91,7 +105,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } text := payload.Event.Text - msg := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date).WithExternalID(payload.EventID).WithContactName("") + msg := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date).WithExternalID(payload.EventID).WithContactName(userName) for _, attURL := range attachmentURLs { msg.WithAttachment(attURL) @@ -102,7 +116,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "Ignoring request, no message") } -func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file moFile) (string, error) { +func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file File) (string, error) { userToken := channel.StringConfigForKey(configUserToken, "") fileApiURL := apiURL + "/files.sharedPublicURL" @@ -187,6 +201,39 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat return status, nil } +func (h handler) GetUserInfo(userSlackID string, channel courier.Channel) (*UserInfo, error) { + resource := "/users.info" + urlStr := apiURL + resource + + req, err := http.NewRequest(http.MethodGet, urlStr, nil) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + req.Header.Add("Authorization", "Bearer "+channel.StringConfigForKey(configBotToken, "")) + + q := req.URL.Query() + q.Add("user", userSlackID) + req.URL.RawQuery = q.Encode() + + rr, err := utils.MakeHTTPRequest(req) + if err != nil { + log := courier.NewChannelLogFromRR("Get User info", channel, courier.NilMsgID, rr).WithError("Request User Info Error", err) + h.Backend().WriteChannelLogs(context.TODO(), []*courier.ChannelLog{log}) + return nil, err + } + + var uInfo *UserInfo + if err := json.Unmarshal(rr.Body, &uInfo); err != nil { + log := courier.NewChannelLogFromRR("Get User info", channel, courier.NilMsgID, rr).WithError("Unmarshal User Info Error", err) + h.Backend().WriteChannelLogs(context.TODO(), []*courier.ChannelLog{log}) + return nil, err + } + + return uInfo, nil +} + type mtPayload struct { Channel string `json:"channel"` Text string `json:"text"` @@ -197,14 +244,15 @@ type moPayload struct { TeamID string `json:"team_id,omitempty"` APIAppID string `json:"api_app_id,omitempty"` Event struct { - Type string `json:"type,omitempty"` - Channel string `json:"channel,omitempty"` - User string `json:"user,omitempty"` - Text string `json:"text,omitempty"` - Ts string `json:"ts,omitempty"` - EventTs string `json:"event_ts,omitempty"` - ChannelType string `json:"channel_type,omitempty"` - Files []moFile `json:"files"` + Type string `json:"type,omitempty"` + Channel string `json:"channel,omitempty"` + User string `json:"user,omitempty"` + Text string `json:"text,omitempty"` + Ts string `json:"ts,omitempty"` + EventTs string `json:"event_ts,omitempty"` + ChannelType string `json:"channel_type,omitempty"` + Files []File `json:"files"` + BotID string `json:"bot_id,omitempty"` } `json:"event,omitempty"` Type string `json:"type,omitempty"` AuthedUsers []string `json:"authed_users,omitempty"` @@ -221,13 +269,7 @@ type moPayload struct { Challenge string `json:"challenge,omitempty"` } -type item struct { - Type string `json:"type,omitempty"` - Channel string `json:"channel,omitempty"` - Ts string `json:"ts,omitempty"` -} - -type moFile struct { +type File struct { ID string `json:"id"` Created int `json:"created"` Timestamp int `json:"timestamp"` @@ -265,6 +307,39 @@ type moFile struct { type fileResponse struct { OK bool `json:"ok"` - File moFile `json:"file"` + File File `json:"file"` Error string `json:"error"` } + +type UserInfo struct { + Ok bool `json:"ok"` + User struct { + ID string `json:"id"` + TeamID string `json:"team_id"` + Name string `json:"name"` + Deleted bool `json:"deleted"` + Color string `json:"color"` + RealName string `json:"real_name"` + Tz string `json:"tz"` + TzLabel string `json:"tz_label"` + TzOffset int `json:"tz_offset"` + Profile struct { + AvatarHash string `json:"avatar_hash"` + StatusText string `json:"status_text"` + StatusEmoji string `json:"status_emoji"` + RealName string `json:"real_name"` + DisplayName string `json:"display_name"` + RealNameNormalized string `json:"real_name_normalized"` + DisplayNameNormalized string `json:"display_name_normalized"` + Email string `json:"email"` + ImageOriginal string `json:"image_original"` + Image24 string `json:"image_24"` + Image32 string `json:"image_32"` + Image48 string `json:"image_48"` + Image72 string `json:"image_72"` + Image192 string `json:"image_192"` + Image512 string `json:"image_512"` + Team string `json:"team"` + } `json:"profile"` + } `json:"user"` +} diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 917fede65..fc68a451e 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -92,7 +92,7 @@ const imageFileMsg = `{ "display_as_bot": false, "ts": "1653417052.881009", "client_msg_id": "0e400b8f-07c4-452f-a13e-2744fcae2558", - "channel": "C03CUQQBHEF", + "channel": "C0123ABCDEF", "subtype": "file_share", "event_ts": "1653417052.881009", "channel_type": "channel" @@ -160,7 +160,7 @@ const audioFileMsg = `{ "display_as_bot": false, "ts": "1653428835.192419", "client_msg_id": "c827a681-2641-44ed-8cd5-854339499a1e", - "channel": "C03CUQQBHEF", + "channel": "C0123ABCDEF", "subtype": "file_share", "event_ts": "1653428835.192419", "channel_type": "channel" @@ -231,7 +231,7 @@ const videoFileMsg = `{ "display_as_bot": false, "ts": "1653427243.620839", "client_msg_id": "72df394d-bfbb-4d90-8db4-cbe5caa76b28", - "channel": "C03CUQQBHEF", + "channel": "C0123ABCDEF", "subtype": "file_share", "event_ts": "1653427243.620839", "channel_type": "channel" @@ -262,7 +262,7 @@ var testCases = []ChannelHandleTestCase{ URL: receiveURL, Headers: map[string]string{}, Data: helloMsg, - URN: Sp("slack:U0123ABCDEF"), + URN: Sp("slack:C0123ABCDEF"), Text: Sp("Hello World!"), Status: 200, Response: "Accepted", @@ -274,7 +274,7 @@ var testCases = []ChannelHandleTestCase{ Headers: map[string]string{}, Data: imageFileMsg, Attachment: Sp("https://files.slack.com/files-pri/T03CN5KTA6S-F03GTH43SSF/download/batata.jpg?pub_secret=39fcf577f2"), - URN: Sp("slack:U0123ABCDEF"), + URN: Sp("slack:C0123ABCDEF"), Text: Sp(""), Status: 200, Response: "Accepted", @@ -286,19 +286,19 @@ var testCases = []ChannelHandleTestCase{ Headers: map[string]string{}, Data: audioFileMsg, Attachment: Sp("https://files.slack.com/files-pri/T03CN5KTA6S-F03GWURCZL4/download/here_we_go_again.mp3?pub_secret=471020b300"), - URN: Sp("slack:U0123ABCDEF"), + URN: Sp("slack:C0123ABCDEF"), Text: Sp(""), Status: 200, Response: "Accepted", ExternalID: Sp("Ev0PV52K21"), }, { - Label: "Receive video file (not allowed,)", + Label: "Receive video file (not allowed)", URL: receiveURL, Headers: map[string]string{}, Data: videoFileMsg, Attachment: nil, - URN: Sp("slack:U0123ABCDEF"), + URN: Sp("slack:C0123ABCDEF"), Text: Sp(""), Status: 200, Response: "Accepted", @@ -363,7 +363,7 @@ func TestVerification(t *testing.T) { func buildMockSlackService(testCases []ChannelHandleTestCase) *httptest.Server { - files := make(map[string]moFile) + files := make(map[string]File) for _, tc := range testCases { var mp moPayload From 5682329f0054a3c24a79868ef45d2743348999e6 Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Fri, 27 May 2022 19:28:42 -0300 Subject: [PATCH 011/294] slack channel handler now can send attachments --- handlers/slack/slack.go | 132 ++++++++++++++++++++++++++++++++++------ 1 file changed, 113 insertions(+), 19 deletions(-) diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index 32cfb5638..d2688b9d3 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -5,7 +5,10 @@ import ( "context" "encoding/json" "fmt" + "io" + "mime/multipart" "net/http" + "net/url" "strings" "time" @@ -169,31 +172,112 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat sendURL := apiURL + "/chat.postMessage" status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - msgPayload := &mtPayload{ - Channel: msg.URN().Path(), - Text: msg.Text(), - } - body, err := json.Marshal(msgPayload) - if err != nil { - return status, err - } + if msg.Text() != "" { + msgPayload := &mtPayload{ + Channel: msg.URN().Path(), + Text: msg.Text(), + } - req, err := http.NewRequest(http.MethodPost, sendURL, bytes.NewReader(body)) - if err != nil { - return status, err + body, err := json.Marshal(msgPayload) + if err != nil { + return status, err + } + + req, err := http.NewRequest(http.MethodPost, sendURL, bytes.NewReader(body)) + if err != nil { + return status, err + } + req.Header.Set("Content-Type", "application/json; charset=utf-8") + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", botToken)) + + rr, err := utils.MakeHTTPRequest(req) + + log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + status.AddLog(log) + + ok, err := jsonparser.GetBoolean([]byte(rr.Body), "ok") + if err != nil || !ok { + return status, err + } } - req.Header.Set("Content-Type", "application/json; charset=utf-8") - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", botToken)) - rr, err := utils.MakeHTTPRequest(req) + if len(msg.Attachments()) > 0 { + fileAttachments := []FileParams{} + for _, attachment := range msg.Attachments() { + _, attURL := handlers.SplitAttachment(attachment) + + req, err := http.NewRequest(http.MethodGet, attURL, nil) + if err != nil { + return status, errors.Wrapf(err, "error building file request") + } + resp, err := utils.MakeHTTPRequest(req) + log := courier.NewChannelLogFromRR("Fetching media", msg.Channel(), msg.ID(), resp).WithError("error fetching media", err) + status.AddLog(log) + if err != nil { + return status, err + } + filename, err := utils.BasePathForURL(attURL) + if err != nil { + return status, err + } + fileAttachments = append(fileAttachments, FileParams{ + File: resp.Body, + FileName: filename, + Channels: msg.URN().Path(), + }) + } + + for _, attParams := range fileAttachments { + uploadURL := apiURL + "/files.upload" + + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + mediaPart, err := writer.CreateFormFile("file", attParams.FileName) + if err != nil { + return status, errors.Wrapf(err, "failed to create file form field") + } + io.Copy(mediaPart, bytes.NewReader(attParams.File)) + + filenamePart, err := writer.CreateFormField("filename") + if err != nil { + return status, errors.Wrapf(err, "failed to create filename form field") + } + io.Copy(filenamePart, strings.NewReader(attParams.FileName)) + + channelsPart, err := writer.CreateFormField("channels") + if err != nil { + return status, errors.Wrapf(err, "failed to create channels form field") + } + io.Copy(channelsPart, strings.NewReader(attParams.Channels)) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) - status.AddLog(log) + writer.Close() - ok, err := jsonparser.GetBoolean([]byte(rr.Body), "ok") - if err != nil || !ok { - return status, err + req, err := http.NewRequest(http.MethodPost, uploadURL, bytes.NewReader(body.Bytes())) + if err != nil { + return status, errors.Wrapf(err, "error building request to file upload endpoint") + } + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", botToken)) + req.Header.Add("Content-Type", writer.FormDataContentType()) + resp, err := utils.MakeHTTPRequest(req) + if err != nil { + return status, errors.Wrapf(err, "error uploading file to slack") + } + { + var fResponse fileResponse + if err := json.Unmarshal([]byte(resp.Body), &fResponse); err != nil { + return status, errors.Errorf("couldn't unmarshal file response: %v", err) + } + + if !fResponse.OK { + return status, errors.Errorf("error uploading file to slack: %s.", fResponse.Error) + } + } + log := courier.NewChannelLogFromRR("uploading file to Slack", msg.Channel(), msg.ID(), resp).WithError("Error uploading file to Slack", err) + + fmt.Println("Video uploaded to slack") + status.AddLog(log) + } } status.SetStatus(courier.MsgWired) @@ -201,6 +285,10 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat return status, nil } +func (h *handler) sendMsgPart(msg courier.Msg, token string, form url.Values) (string, *courier.ChannelLog, error) { + return "", nil, nil +} + func (h handler) GetUserInfo(userSlackID string, channel courier.Channel) (*UserInfo, error) { resource := "/users.info" urlStr := apiURL + resource @@ -343,3 +431,9 @@ type UserInfo struct { } `json:"profile"` } `json:"user"` } + +type FileParams struct { + File []byte `json:"file,omitempty"` + FileName string `json:"filename,omitempty"` + Channels string `json:"channels,omitempty"` +} From cd5b803d46575f1c01eeae892f01f3d5168036ef Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Wed, 1 Jun 2022 16:32:20 -0300 Subject: [PATCH 012/294] refactor slack handler --- handlers/slack/slack.go | 247 +++++++++++++++++++---------------- handlers/slack/slack_test.go | 60 ++++++++- 2 files changed, 190 insertions(+), 117 deletions(-) diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index d2688b9d3..1ab471cae 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -8,7 +8,6 @@ import ( "io" "mime/multipart" "net/http" - "net/url" "strings" "time" @@ -81,12 +80,13 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h var userName string var path string - if payload.Event.ChannelType == "channel" { + if payload.Event.ChannelType == "channel" { //if is a message from a slack channel that bot is in path = payload.Event.Channel - } else if payload.Event.ChannelType == "im" { + } else if payload.Event.ChannelType == "im" { // if is a direct message from a user path = payload.Event.User - userInfo, err := h.GetUserInfo(payload.Event.User, channel) + userInfo, log, err := getUserInfo(payload.Event.User, channel) if err != nil { + h.Backend().WriteChannelLogs(ctx, []*courier.ChannelLog{log}) return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } userName = userInfo.User.RealName @@ -140,7 +140,7 @@ func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file return "", err } - var fResponse fileResponse + var fResponse FileResponse if err := json.Unmarshal([]byte(rr.Body), &fResponse); err != nil { return "", errors.Errorf("couldn't unmarshal file response: %v", err) } @@ -169,133 +169,151 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat if botToken == "" { return nil, fmt.Errorf("missing bot token for SL/slack channel") } - sendURL := apiURL + "/chat.postMessage" status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - if msg.Text() != "" { - msgPayload := &mtPayload{ - Channel: msg.URN().Path(), - Text: msg.Text(), - } + hasError := true - body, err := json.Marshal(msgPayload) - if err != nil { - return status, err - } + for _, attachment := range msg.Attachments() { + fileAttachment, log, err := parseAttachmentToFileParams(msg, attachment) + hasError = err != nil + status.AddLog(log) - req, err := http.NewRequest(http.MethodPost, sendURL, bytes.NewReader(body)) - if err != nil { - return status, err + if fileAttachment != nil { + log, err = sendFilePart(msg, botToken, fileAttachment) + hasError = err != nil + status.AddLog(log) } - req.Header.Set("Content-Type", "application/json; charset=utf-8") - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", botToken)) - - rr, err := utils.MakeHTTPRequest(req) + } - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + if msg.Text() != "" { + log, err := sendTextMsgPart(msg, botToken) + hasError = err != nil status.AddLog(log) + } - ok, err := jsonparser.GetBoolean([]byte(rr.Body), "ok") - if err != nil || !ok { - return status, err - } + if !hasError { + status.SetStatus(courier.MsgWired) } - if len(msg.Attachments()) > 0 { - fileAttachments := []FileParams{} - for _, attachment := range msg.Attachments() { - _, attURL := handlers.SplitAttachment(attachment) + return status, nil +} - req, err := http.NewRequest(http.MethodGet, attURL, nil) - if err != nil { - return status, errors.Wrapf(err, "error building file request") - } - resp, err := utils.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Fetching media", msg.Channel(), msg.ID(), resp).WithError("error fetching media", err) - status.AddLog(log) - if err != nil { - return status, err - } - filename, err := utils.BasePathForURL(attURL) - if err != nil { - return status, err - } - fileAttachments = append(fileAttachments, FileParams{ - File: resp.Body, - FileName: filename, - Channels: msg.URN().Path(), - }) - } +func sendTextMsgPart(msg courier.Msg, token string) (*courier.ChannelLog, error) { + sendURL := apiURL + "/chat.postMessage" - for _, attParams := range fileAttachments { - uploadURL := apiURL + "/files.upload" + msgPayload := &mtPayload{ + Channel: msg.URN().Path(), + Text: msg.Text(), + } - body := &bytes.Buffer{} - writer := multipart.NewWriter(body) - mediaPart, err := writer.CreateFormFile("file", attParams.FileName) - if err != nil { - return status, errors.Wrapf(err, "failed to create file form field") - } - io.Copy(mediaPart, bytes.NewReader(attParams.File)) + body, err := json.Marshal(msgPayload) + if err != nil { + return nil, err + } - filenamePart, err := writer.CreateFormField("filename") - if err != nil { - return status, errors.Wrapf(err, "failed to create filename form field") - } - io.Copy(filenamePart, strings.NewReader(attParams.FileName)) + req, err := http.NewRequest(http.MethodPost, sendURL, bytes.NewReader(body)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json; charset=utf-8") + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) - channelsPart, err := writer.CreateFormField("channels") - if err != nil { - return status, errors.Wrapf(err, "failed to create channels form field") - } - io.Copy(channelsPart, strings.NewReader(attParams.Channels)) + rr, err := utils.MakeHTTPRequest(req) - writer.Close() + log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) - req, err := http.NewRequest(http.MethodPost, uploadURL, bytes.NewReader(body.Bytes())) - if err != nil { - return status, errors.Wrapf(err, "error building request to file upload endpoint") - } - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", botToken)) - req.Header.Add("Content-Type", writer.FormDataContentType()) - resp, err := utils.MakeHTTPRequest(req) - if err != nil { - return status, errors.Wrapf(err, "error uploading file to slack") - } - { - var fResponse fileResponse - if err := json.Unmarshal([]byte(resp.Body), &fResponse); err != nil { - return status, errors.Errorf("couldn't unmarshal file response: %v", err) - } - - if !fResponse.OK { - return status, errors.Errorf("error uploading file to slack: %s.", fResponse.Error) - } - } - log := courier.NewChannelLogFromRR("uploading file to Slack", msg.Channel(), msg.ID(), resp).WithError("Error uploading file to Slack", err) + ok, err := jsonparser.GetBoolean([]byte(rr.Body), "ok") + if err != nil { + return log, err + } - fmt.Println("Video uploaded to slack") - status.AddLog(log) + if !ok { + errDescription, err := jsonparser.GetString([]byte(rr.Body), "error") + if err != nil { + return log, err } + return log, errors.New(errDescription) } + return log, nil +} - status.SetStatus(courier.MsgWired) +func parseAttachmentToFileParams(msg courier.Msg, attachment string) (*FileParams, *courier.ChannelLog, error) { + _, attURL := handlers.SplitAttachment(attachment) - return status, nil + req, err := http.NewRequest(http.MethodGet, attURL, nil) + if err != nil { + return nil, nil, errors.Wrapf(err, "error building file request") + } + resp, err := utils.MakeHTTPRequest(req) + log := courier.NewChannelLogFromRR("Fetching attachment", msg.Channel(), msg.ID(), resp).WithError("error fetching media", err) + + filename, err := utils.BasePathForURL(attURL) + if err != nil { + return nil, log, err + } + return &FileParams{ + File: resp.Body, + FileName: filename, + Channels: msg.URN().Path(), + }, log, nil } -func (h *handler) sendMsgPart(msg courier.Msg, token string, form url.Values) (string, *courier.ChannelLog, error) { - return "", nil, nil +func sendFilePart(msg courier.Msg, token string, fileParams *FileParams) (*courier.ChannelLog, error) { + uploadURL := apiURL + "/files.upload" + + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + mediaPart, err := writer.CreateFormFile("file", fileParams.FileName) + if err != nil { + return nil, errors.Wrapf(err, "failed to create file form field") + } + io.Copy(mediaPart, bytes.NewReader(fileParams.File)) + + filenamePart, err := writer.CreateFormField("filename") + if err != nil { + return nil, errors.Wrapf(err, "failed to create filename form field") + } + io.Copy(filenamePart, strings.NewReader(fileParams.FileName)) + + channelsPart, err := writer.CreateFormField("channels") + if err != nil { + return nil, errors.Wrapf(err, "failed to create channels form field") + } + io.Copy(channelsPart, strings.NewReader(fileParams.Channels)) + + writer.Close() + + req, err := http.NewRequest(http.MethodPost, uploadURL, bytes.NewReader(body.Bytes())) + if err != nil { + return nil, errors.Wrapf(err, "error building request to file upload endpoint") + } + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) + req.Header.Add("Content-Type", writer.FormDataContentType()) + resp, err := utils.MakeHTTPRequest(req) + if err != nil { + return nil, errors.Wrapf(err, "error uploading file to slack") + } + + var fr FileResponse + if err := json.Unmarshal([]byte(resp.Body), &fr); err != nil { + return nil, errors.Errorf("couldn't unmarshal file response: %v", err) + } + + if !fr.OK { + return nil, errors.Errorf("error uploading file to slack: %s.", fr.Error) + } + + return courier.NewChannelLogFromRR("uploading file to Slack", msg.Channel(), msg.ID(), resp).WithError("Error uploading file to Slack", err), nil } -func (h handler) GetUserInfo(userSlackID string, channel courier.Channel) (*UserInfo, error) { +func getUserInfo(userSlackID string, channel courier.Channel) (*UserInfo, *courier.ChannelLog, error) { resource := "/users.info" urlStr := apiURL + resource req, err := http.NewRequest(http.MethodGet, urlStr, nil) if err != nil { - return nil, err + return nil, nil, err } req.Header.Add("Content-Type", "application/x-www-form-urlencoded") @@ -308,25 +326,25 @@ func (h handler) GetUserInfo(userSlackID string, channel courier.Channel) (*User rr, err := utils.MakeHTTPRequest(req) if err != nil { log := courier.NewChannelLogFromRR("Get User info", channel, courier.NilMsgID, rr).WithError("Request User Info Error", err) - h.Backend().WriteChannelLogs(context.TODO(), []*courier.ChannelLog{log}) - return nil, err + return nil, log, err } var uInfo *UserInfo if err := json.Unmarshal(rr.Body, &uInfo); err != nil { log := courier.NewChannelLogFromRR("Get User info", channel, courier.NilMsgID, rr).WithError("Unmarshal User Info Error", err) - h.Backend().WriteChannelLogs(context.TODO(), []*courier.ChannelLog{log}) - return nil, err + return nil, log, err } - return uInfo, nil + return uInfo, nil, nil } +// mtPayload is a struct that represents the body of a SendMmsg text part type mtPayload struct { Channel string `json:"channel"` Text string `json:"text"` } +// moPayload is a struct that represents message payload from message type event type moPayload struct { Token string `json:"token,omitempty"` TeamID string `json:"team_id,omitempty"` @@ -357,6 +375,7 @@ type moPayload struct { Challenge string `json:"challenge,omitempty"` } +// File is a struct that represents file item that can be present in Files list in message event, or in FileResponse or in FileParams type File struct { ID string `json:"id"` Created int `json:"created"` @@ -393,12 +412,22 @@ type File struct { HasRichPreview bool `json:"has_rich_preview"` } -type fileResponse struct { +// FileResponse is a struct that represents the response from a request in files.sharedPublicURL to make public and shareable a file that is sent in a message, more information see https://api.slack.com/methods/files.sharedPublicURL. +type FileResponse struct { OK bool `json:"ok"` File File `json:"file"` Error string `json:"error"` } +// FileParams is a struct that represents the request params send to slack api files.upload method to send a file to a channel conversation or a direct message conversation with a user, more +// information see https://api.slack.com/methods/files.upload. +type FileParams struct { + File []byte `json:"file,omitempty"` + FileName string `json:"filename,omitempty"` + Channels string `json:"channels,omitempty"` +} + +// UserInfo is a struct that represents the response from request in users.info slack api method, more information see https://api.slack.com/methods/users.info. type UserInfo struct { Ok bool `json:"ok"` User struct { @@ -431,9 +460,3 @@ type UserInfo struct { } `json:"profile"` } `json:"user"` } - -type FileParams struct { - File []byte `json:"file,omitempty"` - FileName string `json:"filename,omitempty"` - Channels string `json:"channels,omitempty"` -} diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index fc68a451e..38fd3c408 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -6,6 +6,7 @@ import ( "log" "net/http" "net/http/httptest" + "strings" "testing" "github.com/buger/jsonparser" @@ -256,7 +257,7 @@ func setSendUrl(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, apiURL = s.URL } -var testCases = []ChannelHandleTestCase{ +var handleTestCases = []ChannelHandleTestCase{ { Label: "Receive Hello Msg", URL: receiveURL, @@ -326,7 +327,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendUrl, }, { - Label: "Send Text Error", + Label: "Send Text Auth Error", Text: "Hello", URN: "slack:U0123ABCDEF", Status: "E", ResponseBody: `{"ok":false,"error":"invalid_auth"}`, @@ -336,17 +337,45 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, } +var fileSendTestCases = []ChannelSendTestCase{ + { + Label: "Send Image", + Text: "", URN: "slack:U0123ABCDEF", + Status: "W", + Attachments: []string{"image/jpeg:https://foo.bar/image.png"}, + Responses: map[MockedRequest]MockedResponse{ + { + Method: "POST", + Path: "/files.upload", + BodyContains: "image.png", + }: { + Status: 200, + Body: `{"ok":true,"file":{"id":"F1L3SL4CK1D"}}`, + }, + }, + SendPrep: setSendUrl, + }, +} + func TestHandler(t *testing.T) { - slackServiceMock := buildMockSlackService(testCases) + slackServiceMock := buildMockSlackService(handleTestCases) defer slackServiceMock.Close() - RunChannelTestCases(t, testChannels, newHandler(), testCases) + RunChannelTestCases(t, testChannels, newHandler(), handleTestCases) } func TestSending(t *testing.T) { RunChannelSendTestCases(t, testChannels[0], newHandler(), defaultSendTestCases, nil) } +func TestSendFiles(t *testing.T) { + fileServer := buildMockAttachmentFileServer() + defer fileServer.Close() + fileSendTestCases := mockAttachmentURLs(fileServer, fileSendTestCases) + + RunChannelSendTestCases(t, testChannels[0], newHandler(), fileSendTestCases, nil) +} + func TestVerification(t *testing.T) { RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ {Label: "Valid token", URL: receiveURL, Status: 200, @@ -361,6 +390,14 @@ func TestVerification(t *testing.T) { }) } +func buildMockAttachmentFileServer() *httptest.Server { + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + w.WriteHeader(200) + w.Write([]byte("filetype... ...file bytes... ...end")) + })) +} + func buildMockSlackService(testCases []ChannelHandleTestCase) *httptest.Server { files := make(map[string]File) @@ -397,10 +434,23 @@ func buildMockSlackService(testCases []ChannelHandleTestCase) *httptest.Server { w.Write([]byte(`{"ok": "false", "error": "file not found"}`)) return } - json.NewEncoder(w).Encode(fileResponse{OK: true, Error: "", File: file}) + json.NewEncoder(w).Encode(FileResponse{OK: true, Error: "", File: file}) })) apiURL = server.URL return server } + +func mockAttachmentURLs(fileServer *httptest.Server, testCases []ChannelSendTestCase) []ChannelSendTestCase { + casesWithMockedUrls := make([]ChannelSendTestCase, len(testCases)) + + for i, testCase := range testCases { + mockedCase := testCase + for j, attachment := range testCase.Attachments { + mockedCase.Attachments[j] = strings.Replace(attachment, "https://foo.bar", fileServer.URL, 1) + } + casesWithMockedUrls[i] = mockedCase + } + return casesWithMockedUrls +} From cd66e26caf7366e50af7d81475791951594986bb Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Mon, 13 Jun 2022 15:40:24 -0300 Subject: [PATCH 013/294] update gocommon --- go.mod | 4 +--- go.sum | 8 ++------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 4f2181609..2c7695184 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/jmoiron/sqlx v1.3.4 github.com/lib/pq v1.10.4 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.19.1 + github.com/nyaruka/gocommon v1.22.0 github.com/nyaruka/librato v1.0.0 github.com/nyaruka/null v1.1.1 github.com/nyaruka/redisx v0.2.1 @@ -56,5 +56,3 @@ require ( gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) - -replace github.com/nyaruka/gocommon => github.com/Ilhasoft/gocommon v1.19.1-slack-develop diff --git a/go.sum b/go.sum index f7ed14e81..eeb79e798 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,3 @@ -github.com/Ilhasoft/gocommon v1.16.2-slack-develop h1:pAd+LMH7BEOFxUIeJ1EGJeaMPbMolHpChHmalvjmQbQ= -github.com/Ilhasoft/gocommon v1.16.2-slack-develop/go.mod h1:pk8L9T79VoKO8OWTiZbtUutFPI3sGGKB5u8nNWDKuGE= -github.com/Ilhasoft/gocommon v1.19.1-slack-develop h1:aDh3PyVeFtqFgA/KVBaI/etVhQZ1pPXWnwQo4fM6R4I= -github.com/Ilhasoft/gocommon v1.19.1-slack-develop/go.mod h1:JrQSLAPo9ezSy1AzsJ1zDr1HW0/eu+aipICJkN/+kpg= github.com/antchfx/xmlquery v0.0.0-20181223105952-355641961c92 h1:4EgP6xLAdrD/TRlbSw4n2W6h68K2P3+R7lKqFoL5U9Q= github.com/antchfx/xmlquery v0.0.0-20181223105952-355641961c92/go.mod h1:/+CnyD/DzHRnv2eRxrVbieRU/FIF6N0C+7oTtyUtCKk= github.com/antchfx/xpath v0.0.0-20181208024549-4bbdf6db12aa h1:lL66YnJWy1tHlhjSx8fXnpgmv8kQVYnI4ilbYpNB6Zs= @@ -76,8 +72,8 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.19.1 h1:miVSFCqSEe1pKAID/PWqwRBtdvPnw6kQZC/Bz9tYVgQ= -github.com/nyaruka/gocommon v1.19.1/go.mod h1:JrQSLAPo9ezSy1AzsJ1zDr1HW0/eu+aipICJkN/+kpg= +github.com/nyaruka/gocommon v1.22.0 h1:ptlZftc7ZKDF81NRUW2H4NOlIQO144m3wvkTO1d+yms= +github.com/nyaruka/gocommon v1.22.0/go.mod h1:cv9r6amof1gSktfPZROClZhLFzdSIH/N9KbW6Nny4g8= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.1.1 h1:kRy1Luj7jUHWEFqc2J6VXrKYi/beLEZdS1C7rA6vqTE= From 1ff03fc90ace37c630dafb3e15c81f4e23667c27 Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Wed, 22 Jun 2022 12:09:59 -0300 Subject: [PATCH 014/294] tweaks slack channel tests and handler --- handlers/slack/slack.go | 120 ++++--------------- handlers/slack/slack_test.go | 219 ++++++++--------------------------- 2 files changed, 73 insertions(+), 266 deletions(-) diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index 1ab471cae..bb08b6fd7 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -54,7 +54,7 @@ func handleURLVerification(ctx context.Context, channel courier.Channel, w http. validationToken := channel.ConfigForKey(configValidationToken, "") if validationToken != payload.Token { w.WriteHeader(http.StatusForbidden) - return nil, fmt.Errorf("Wrong validation token for channel: %s", channel.UUID()) + return nil, fmt.Errorf("wrong validation token for channel: %s", channel.UUID()) } w.Header().Set("Content-Type", "text/plain") w.WriteHeader(http.StatusOK) @@ -74,25 +74,17 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } // if event is not a message or is from the bot ignore it - if strings.Contains(payload.Event.Type, "message") && payload.Event.BotID == "" { + if payload.Event.Type == "message" && payload.Event.BotID == "" && payload.Event.ChannelType == "im" { date := time.Unix(int64(payload.EventTime), 0) - var userName string - var path string - if payload.Event.ChannelType == "channel" { //if is a message from a slack channel that bot is in - path = payload.Event.Channel - } else if payload.Event.ChannelType == "im" { // if is a direct message from a user - path = payload.Event.User - userInfo, log, err := getUserInfo(payload.Event.User, channel) - if err != nil { - h.Backend().WriteChannelLogs(ctx, []*courier.ChannelLog{log}) - return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) - } - userName = userInfo.User.RealName + userInfo, log, err := getUserInfo(payload.Event.User, channel) + if err != nil { + h.Backend().WriteChannelLogs(ctx, []*courier.ChannelLog{log}) + return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } - urn, err := urns.NewURNFromParts(urns.SlackScheme, path, "", userName) + urn, err := urns.NewURNFromParts(urns.SlackScheme, payload.Event.User, "", "") if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } @@ -108,7 +100,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } text := payload.Event.Text - msg := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date).WithExternalID(payload.EventID).WithContactName(userName) + msg := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date).WithExternalID(payload.EventID).WithContactName(userInfo.User.RealName) for _, attURL := range attachmentURLs { msg.WithAttachment(attURL) @@ -338,125 +330,61 @@ func getUserInfo(userSlackID string, channel courier.Channel) (*UserInfo, *couri return uInfo, nil, nil } -// mtPayload is a struct that represents the body of a SendMmsg text part +// mtPayload is a struct that represents the body of a SendMmsg text part. +// https://api.slack.com/methods/chat.postMessage type mtPayload struct { Channel string `json:"channel"` Text string `json:"text"` } -// moPayload is a struct that represents message payload from message type event +// moPayload is a struct that represents message payload from message type event. +// https://api.slack.com/events/message.im type moPayload struct { - Token string `json:"token,omitempty"` - TeamID string `json:"team_id,omitempty"` - APIAppID string `json:"api_app_id,omitempty"` - Event struct { + Token string `json:"token,omitempty"` + Event struct { Type string `json:"type,omitempty"` Channel string `json:"channel,omitempty"` User string `json:"user,omitempty"` Text string `json:"text,omitempty"` - Ts string `json:"ts,omitempty"` - EventTs string `json:"event_ts,omitempty"` ChannelType string `json:"channel_type,omitempty"` Files []File `json:"files"` BotID string `json:"bot_id,omitempty"` } `json:"event,omitempty"` - Type string `json:"type,omitempty"` - AuthedUsers []string `json:"authed_users,omitempty"` - AuthedTeams []string `json:"authed_teams,omitempty"` - Authorizations []struct { - EnterpriseID string `json:"enterprise_id,omitempty"` - TeamID string `json:"team_id,omitempty"` - UserID string `json:"user_id,omitempty"` - IsBot bool `json:"is_bot,omitempty"` - } `json:"authorizations,omitempty"` - EventContext string `json:"event_context,omitempty"` - EventID string `json:"event_id,omitempty"` - EventTime int `json:"event_time,omitempty"` - Challenge string `json:"challenge,omitempty"` + Type string `json:"type,omitempty"` + EventID string `json:"event_id,omitempty"` + EventTime int `json:"event_time,omitempty"` + Challenge string `json:"challenge,omitempty"` } // File is a struct that represents file item that can be present in Files list in message event, or in FileResponse or in FileParams type File struct { ID string `json:"id"` - Created int `json:"created"` - Timestamp int `json:"timestamp"` - Name string `json:"name"` - Title string `json:"title"` Mimetype string `json:"mimetype"` - Filetype string `json:"filetype"` - PrettyType string `json:"pretty_type"` - User string `json:"user"` - Editable bool `json:"editable"` - Size int `json:"size"` - Mode string `json:"mode"` - IsExternal bool `json:"is_external"` - ExternalType string `json:"external_type"` - IsPublic bool `json:"is_public"` - PublicURLShared bool `json:"public_url_shared"` - DisplayAsBot bool `json:"display_as_bot"` - Username string `json:"username"` - URLPrivate string `json:"url_private"` URLPrivateDownload string `json:"url_private_download"` - MediaDisplayType string `json:"media_display_type"` - Thumb64 string `json:"thumb_64"` - Thumb80 string `json:"thumb_80"` - Thumb360 string `json:"thumb_360"` - Thumb360W int `json:"thumb_360_w"` - Thumb360H int `json:"thumb_360_h"` - Thumb160 string `json:"thumb_160"` - OriginalW int `json:"original_w"` - OriginalH int `json:"original_h"` - ThumbTiny string `json:"thumb_tiny"` - Permalink string `json:"permalink"` PermalinkPublic string `json:"permalink_public"` - HasRichPreview bool `json:"has_rich_preview"` } -// FileResponse is a struct that represents the response from a request in files.sharedPublicURL to make public and shareable a file that is sent in a message, more information see https://api.slack.com/methods/files.sharedPublicURL. +// FileResponse is a struct that represents the response from a request in files.sharedPublicURL to make public and shareable a file that is sent in a message. +// https://api.slack.com/methods/files.sharedPublicURL. type FileResponse struct { OK bool `json:"ok"` File File `json:"file"` Error string `json:"error"` } -// FileParams is a struct that represents the request params send to slack api files.upload method to send a file to a channel conversation or a direct message conversation with a user, more -// information see https://api.slack.com/methods/files.upload. +// FileParams is a struct that represents the request params send to slack api files.upload method to send a file to conversation. +// https://api.slack.com/methods/files.upload. type FileParams struct { File []byte `json:"file,omitempty"` FileName string `json:"filename,omitempty"` Channels string `json:"channels,omitempty"` } -// UserInfo is a struct that represents the response from request in users.info slack api method, more information see https://api.slack.com/methods/users.info. +// UserInfo is a struct that represents the response from request in users.info slack api method. +// https://api.slack.com/methods/users.info. type UserInfo struct { Ok bool `json:"ok"` User struct { - ID string `json:"id"` - TeamID string `json:"team_id"` - Name string `json:"name"` - Deleted bool `json:"deleted"` - Color string `json:"color"` RealName string `json:"real_name"` - Tz string `json:"tz"` - TzLabel string `json:"tz_label"` - TzOffset int `json:"tz_offset"` - Profile struct { - AvatarHash string `json:"avatar_hash"` - StatusText string `json:"status_text"` - StatusEmoji string `json:"status_emoji"` - RealName string `json:"real_name"` - DisplayName string `json:"display_name"` - RealNameNormalized string `json:"real_name_normalized"` - DisplayNameNormalized string `json:"display_name_normalized"` - Email string `json:"email"` - ImageOriginal string `json:"image_original"` - Image24 string `json:"image_24"` - Image32 string `json:"image_32"` - Image48 string `json:"image_48"` - Image72 string `json:"image_72"` - Image192 string `json:"image_192"` - Image512 string `json:"image_512"` - Team string `json:"team"` - } `json:"profile"` } `json:"user"` } diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 38fd3c408..1c9075d8c 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -29,12 +29,12 @@ const helloMsg = `{ "api_app_id": "A0PNCHHK2", "event": { "type": "message", - "channel": "C0123ABCDEF", + "channel": "U0123ABCDEF", "user": "U0123ABCDEF", "text": "Hello World!", "ts": "1355517523.000005", "event_ts": "1355517523.000005", - "channel_type": "channel" + "channel_type": "im" }, "type": "event_callback", "authed_teams": [ @@ -54,64 +54,18 @@ const imageFileMsg = `{ "files": [ { "id": "F03GTH43SSF", - "created": 1653417049, - "timestamp": 1653417049, - "name": "batata.jpg", - "title": "batata.jpg", "mimetype": "image/jpeg", - "filetype": "jpg", - "pretty_type": "JPEG", - "user": "U0123ABCDEF", - "editable": false, - "size": 7130, - "mode": "hosted", - "is_external": false, - "external_type": "", - "is_public": true, - "public_url_shared": false, - "display_as_bot": false, - "username": "", - "url_private": "https://files.slack.com/files-pri/T03CN5KTA6S-F03GTH43SSF/batata.jpg", "url_private_download": "https://files.slack.com/files-pri/T03CN5KTA6S-F03GTH43SSF/download/batata.jpg", - "media_display_type": "unknown", - "thumb_64": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GTH43SSF-75138e6784/batata_64.jpg", - "thumb_80": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GTH43SSF-75138e6784/batata_80.jpg", - "thumb_360": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GTH43SSF-75138e6784/batata_360.jpg", - "thumb_360_w": 360, - "thumb_360_h": 360, - "thumb_160": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GTH43SSF-75138e6784/batata_160.jpg", - "original_w": 400, - "original_h": 400, - "thumb_tiny": "AwAwADDTooooAKKY7Y4HWmjnqalysOxLRTUJJxTqadxBTS4HvRIcLURIFTKVhpDZJhu6UAse1IuCSR16U/NZPXUvYWNyOq81MDkZFQk9xT4+5rSL6EseRkYNRtCD0JFSUVbSZJWW3dGzvz7YpTuB5VvwFWKKTgh3IQpYdxUoGBS0U0rA2f/Z", - "permalink": "https://teste-apigrupo.slack.com/files/U0123ABCDEF/F03GTH43SSF/batata.jpg", - "permalink_public": "https://slack-files.com/T03CN5KTA6S-F03GTH43SSF-39fcf577f2", - "has_rich_preview": false + "permalink_public": "https://slack-files.com/T03CN5KTA6S-F03GTH43SSF-39fcf577f2" } ], - "upload": false, "user": "U0123ABCDEF", - "display_as_bot": false, - "ts": "1653417052.881009", - "client_msg_id": "0e400b8f-07c4-452f-a13e-2744fcae2558", - "channel": "C0123ABCDEF", - "subtype": "file_share", - "event_ts": "1653417052.881009", - "channel_type": "channel" + "channel": "U0123ABCDEF", + "channel_type": "im" }, "type": "event_callback", "event_id": "Ev0PV52K21", - "event_time": 1653417052, - "authorizations": [ - { - "enterprise_id": null, - "team_id": "T03CN5KTA6S", - "user_id": "U03G81FQM98", - "is_bot": true, - "is_enterprise_install": false - } - ], - "is_ext_shared_channel": false, - "event_context": "4-eyJldCI6Im1lc3NhZ2UiLCJ0aWQiOiJUMDNDTjVLVEE2UyIsImFpZCI6IkEwM0ZUQzhNWjYzIiwiY2lkIjoiQzAzQ1VRUUJIRUYifQ" + "event_time": 1653417052 } ` @@ -125,61 +79,18 @@ const audioFileMsg = `{ "files": [ { "id": "F03GWURCZL4", - "created": 1653428828, - "timestamp": 1653428828, - "name": "here we go again.mp3", - "title": "here we go again.mp3", "mimetype": "audio/mpeg", - "filetype": "mp3", - "pretty_type": "MP3", - "user": "U0123ABCDEF", - "editable": false, - "size": 102122, - "mode": "hosted", - "is_external": false, - "external_type": "", - "is_public": true, - "public_url_shared": false, - "display_as_bot": false, - "username": "", - "transcription": { - "status": "none" - }, - "url_private": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GWURCZL4-9aaa1171c6/here_we_go_again_audio.mp4", "url_private_download": "https://files.slack.com/files-pri/T03CN5KTA6S-F03GWURCZL4/download/here_we_go_again.mp3", - "duration_ms": 3187, - "aac": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GWURCZL4-9aaa1171c6/here_we_go_again_audio.mp4", - "audio_wave_samples": [0,0,0,3,5,2,3,6,9,10,9,8,5,3,9,19,22,23,24,25,25,30,28,13,10,10,8,7,4,1,5,7,9,10,9,12,56,35,59,15,10,10,8,6,3,3,6,8,10,10,8,5,2,3,6,8,10,10,22,50,42,20,59,73,30,14,26,67,65,72,72,86,94,36,12,42,100,91,91,86,54,40,23,15,7,5,8,9,10,8,6,3,2,5,8,10,9,8,5,2], - "media_display_type": "audio", - "permalink": "https://teste-apigrupo.slack.com/files/U0123ABCDEF/F03GWURCZL4/here_we_go_again.mp3", - "permalink_public": "https://slack-files.com/T03CN5KTA6S-F03GWURCZL4-471020b300", - "has_rich_preview": false + "permalink_public": "https://slack-files.com/T03CN5KTA6S-F03GWURCZL4-471020b300" } ], - "upload": false, "user": "U0123ABCDEF", - "display_as_bot": false, - "ts": "1653428835.192419", - "client_msg_id": "c827a681-2641-44ed-8cd5-854339499a1e", - "channel": "C0123ABCDEF", - "subtype": "file_share", - "event_ts": "1653428835.192419", - "channel_type": "channel" + "channel": "U0123ABCDEF", + "channel_type": "im" }, "type": "event_callback", "event_id": "Ev0PV52K21", - "event_time": 1653428835, - "authorizations": [ - { - "enterprise_id": null, - "team_id": "T03CN5KTA6S", - "user_id": "U03G81FQM98", - "is_bot": true, - "is_enterprise_install": false - } - ], - "is_ext_shared_channel": false, - "event_context": "4-eyJldCI6Im1lc3NhZ2UiLCJ0aWQiOiJUMDNDTjVLVEE2UyIsImFpZCI6IkEwM0ZUQzhNWjYzIiwiY2lkIjoiQzAzQ1VRUUJIRUYifQ" + "event_time": 1653428835 } ` @@ -193,64 +104,19 @@ const videoFileMsg = `{ "files": [ { "id": "F03GDSSMC79", - "created": 1653427226, - "timestamp": 1653427226, - "name": "Walk Cycle Animation sample.mp4", - "title": "Walk Cycle Animation sample.mp4", "mimetype": "video/mp4", - "filetype": "mp4", - "pretty_type": "MPEG 4 Video", - "user": "U0123ABCDEF", - "editable": false, - "size": 767148, - "mode": "hosted", - "is_external": false, - "external_type": "", - "is_public": true, - "public_url_shared": false, - "display_as_bot": false, - "username": "", - "transcription": { - "status": "none" - }, - "mp4": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GDSSMC79-0af57254d8/walk_cycle_animation_sample.mp4", - "url_private": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GDSSMC79-0af57254d8/walk_cycle_animation_sample.mp4", "url_private_download": "https://files.slack.com/files-pri/T03CN5KTA6S-F03GDSSMC79/download/walk_cycle_animation_sample.mp4", - "hls": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GDSSMC79-0af57254d8/file.m3u8", - "duration_ms": 19953, - "media_display_type": "video", - "thumb_video": "https://files.slack.com/files-tmb/T03CN5KTA6S-F03GDSSMC79-0af57254d8/walk_cycle_animation_sample_thumb_video.jpeg", - "thumb_video_w": 640, - "thumb_video_h": 360, "permalink": "https://teste-apigrupo.slack.com/files/U0123ABCDEF/F03GDSSMC79/walk_cycle_animation_sample.mp4", - "permalink_public": "https://slack-files.com/T03CN5KTA6S-F03GDSSMC79-805aa1d85f", - "has_rich_preview": false + "permalink_public": "https://slack-files.com/T03CN5KTA6S-F03GDSSMC79-805aa1d85f" } ], - "upload": false, "user": "U0123ABCDEF", - "display_as_bot": false, - "ts": "1653427243.620839", - "client_msg_id": "72df394d-bfbb-4d90-8db4-cbe5caa76b28", - "channel": "C0123ABCDEF", - "subtype": "file_share", - "event_ts": "1653427243.620839", - "channel_type": "channel" + "channel": "U0123ABCDEF", + "channel_type": "im" }, "type": "event_callback", "event_id": "Ev0PV52K21", - "event_time": 1653427243, - "authorizations": [ - { - "enterprise_id": null, - "team_id": "T03CN5KTA6S", - "user_id": "U03G81FQM98", - "is_bot": true, - "is_enterprise_install": false - } - ], - "is_ext_shared_channel": false, - "event_context": "4-eyJldCI6Im1lc3NhZ2UiLCJ0aWQiOiJUMDNDTjVLVEE2UyIsImFpZCI6IkEwM0ZUQzhNWjYzIiwiY2lkIjoiQzAzQ1VRUUJIRUYifQ" + "event_time": 1653427243 }` func setSendUrl(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { @@ -263,7 +129,7 @@ var handleTestCases = []ChannelHandleTestCase{ URL: receiveURL, Headers: map[string]string{}, Data: helloMsg, - URN: Sp("slack:C0123ABCDEF"), + URN: Sp("slack:U0123ABCDEF"), Text: Sp("Hello World!"), Status: 200, Response: "Accepted", @@ -275,7 +141,7 @@ var handleTestCases = []ChannelHandleTestCase{ Headers: map[string]string{}, Data: imageFileMsg, Attachment: Sp("https://files.slack.com/files-pri/T03CN5KTA6S-F03GTH43SSF/download/batata.jpg?pub_secret=39fcf577f2"), - URN: Sp("slack:C0123ABCDEF"), + URN: Sp("slack:U0123ABCDEF"), Text: Sp(""), Status: 200, Response: "Accepted", @@ -287,7 +153,7 @@ var handleTestCases = []ChannelHandleTestCase{ Headers: map[string]string{}, Data: audioFileMsg, Attachment: Sp("https://files.slack.com/files-pri/T03CN5KTA6S-F03GWURCZL4/download/here_we_go_again.mp3?pub_secret=471020b300"), - URN: Sp("slack:C0123ABCDEF"), + URN: Sp("slack:U0123ABCDEF"), Text: Sp(""), Status: 200, Response: "Accepted", @@ -299,7 +165,7 @@ var handleTestCases = []ChannelHandleTestCase{ Headers: map[string]string{}, Data: videoFileMsg, Attachment: nil, - URN: Sp("slack:C0123ABCDEF"), + URN: Sp("slack:U0123ABCDEF"), Text: Sp(""), Status: 200, Response: "Accepted", @@ -310,11 +176,11 @@ var handleTestCases = []ChannelHandleTestCase{ var defaultSendTestCases = []ChannelSendTestCase{ { Label: "Plain Send", - Text: "Simple Message", URN: "slack:C0123ABCDEF", + Text: "Simple Message", URN: "slack:U0123ABCDEF", Status: "W", - ResponseBody: `{"ok":true,"channel":"C0123ABCDEF"}`, + ResponseBody: `{"ok":true,"channel":"U0123ABCDEF"}`, ResponseStatus: 200, - RequestBody: `{"channel":"C0123ABCDEF","text":"Simple Message"}`, + RequestBody: `{"channel":"U0123ABCDEF","text":"Simple Message"}`, SendPrep: setSendUrl, }, { @@ -416,25 +282,38 @@ func buildMockSlackService(testCases []ChannelHandleTestCase) *httptest.Server { } server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - byteBody, err := io.ReadAll(r.Body) - f, err := jsonparser.GetString(byteBody, "file") - if err != nil { - log.Fatal(err) - } - defer r.Body.Close() + switch r.URL.Path { - file, ok := files[f] + case "/users.info": - if file.Mimetype == "video/mp4" { - w.Write([]byte(`{"ok":"false","error":"public_video_not_allowed"}`)) - return - } + w.WriteHeader(http.StatusOK) + w.Write([]byte(`{"user":{"real_name":"dummy user"}}`)) + + case "/files.sharedPublicURL": + + byteBody, err := io.ReadAll(r.Body) + if err != nil { + log.Fatal(err) + } + f, err := jsonparser.GetString(byteBody, "file") + if err != nil { + log.Fatal(err) + } + defer r.Body.Close() + + file, ok := files[f] - if !ok { - w.Write([]byte(`{"ok": "false", "error": "file not found"}`)) - return + if file.Mimetype == "video/mp4" { + w.Write([]byte(`{"ok":"false","error":"public_video_not_allowed"}`)) + return + } + + if !ok { + w.Write([]byte(`{"ok": "false", "error": "file not found"}`)) + return + } + json.NewEncoder(w).Encode(FileResponse{OK: true, Error: "", File: file}) } - json.NewEncoder(w).Encode(FileResponse{OK: true, Error: "", File: file}) })) apiURL = server.URL From e6fd67cac65ab3ea952ee1fa4b117d88054fa9ba Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Mon, 18 Jul 2022 16:42:22 -0300 Subject: [PATCH 015/294] slack channel DescribeURN --- handlers/slack/slack.go | 26 ++++++++------------------ handlers/slack/slack_test.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index bb08b6fd7..21ea590a5 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -78,12 +78,6 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h date := time.Unix(int64(payload.EventTime), 0) - userInfo, log, err := getUserInfo(payload.Event.User, channel) - if err != nil { - h.Backend().WriteChannelLogs(ctx, []*courier.ChannelLog{log}) - return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) - } - urn, err := urns.NewURNFromParts(urns.SlackScheme, payload.Event.User, "", "") if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) @@ -100,7 +94,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } text := payload.Event.Text - msg := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date).WithExternalID(payload.EventID).WithContactName(userInfo.User.RealName) + msg := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date).WithExternalID(payload.EventID) for _, attURL := range attachmentURLs { msg.WithAttachment(attURL) @@ -299,35 +293,31 @@ func sendFilePart(msg courier.Msg, token string, fileParams *FileParams) (*couri return courier.NewChannelLogFromRR("uploading file to Slack", msg.Channel(), msg.ID(), resp).WithError("Error uploading file to Slack", err), nil } -func getUserInfo(userSlackID string, channel courier.Channel) (*UserInfo, *courier.ChannelLog, error) { +// DescribeURN handles Slack user details +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN) (map[string]string, error) { resource := "/users.info" urlStr := apiURL + resource - req, err := http.NewRequest(http.MethodGet, urlStr, nil) - if err != nil { - return nil, nil, err - } + req, _ := http.NewRequest(http.MethodGet, urlStr, nil) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") req.Header.Add("Authorization", "Bearer "+channel.StringConfigForKey(configBotToken, "")) q := req.URL.Query() - q.Add("user", userSlackID) + q.Add("user", urn.Path()) req.URL.RawQuery = q.Encode() rr, err := utils.MakeHTTPRequest(req) if err != nil { - log := courier.NewChannelLogFromRR("Get User info", channel, courier.NilMsgID, rr).WithError("Request User Info Error", err) - return nil, log, err + return nil, fmt.Errorf("request user info error:%s\n%s", err, rr.Response) } var uInfo *UserInfo if err := json.Unmarshal(rr.Body, &uInfo); err != nil { - log := courier.NewChannelLogFromRR("Get User info", channel, courier.NilMsgID, rr).WithError("Unmarshal User Info Error", err) - return nil, log, err + return nil, fmt.Errorf("unmarshal user info error:%s", err) } - return uInfo, nil, nil + return map[string]string{"name": uInfo.User.RealName}, nil } // mtPayload is a struct that represents the body of a SendMmsg text part. diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 1c9075d8c..b5965a8c4 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -1,6 +1,7 @@ package slack import ( + "context" "encoding/json" "io" "log" @@ -12,6 +13,8 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/urns" + "github.com/stretchr/testify/assert" ) const ( @@ -221,6 +224,23 @@ var fileSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendUrl, }, + { + Label: "Send Image", + Text: "", URN: "slack:U0123ABCDEF", + Status: "W", + Attachments: []string{"image/jpeg:https://foo.bar/image.png"}, + Responses: map[MockedRequest]MockedResponse{ + { + Method: "POST", + Path: "/files.upload", + BodyContains: "image.png", + }: { + Status: 200, + Body: `{"ok":true,"file":{"id":"F1L3SL4CK1D"}}`, + }, + }, + SendPrep: setSendUrl, + }, } func TestHandler(t *testing.T) { @@ -333,3 +353,17 @@ func mockAttachmentURLs(fileServer *httptest.Server, testCases []ChannelSendTest } return casesWithMockedUrls } + +func TestDescribe(t *testing.T) { + server := buildMockSlackService([]ChannelHandleTestCase{}) + defer server.Close() + + handler := newHandler().(courier.URNDescriber) + urn, _ := urns.NewURNFromParts(urns.SlackScheme, "U012345", "", "") + + data := map[string]string{"name": "dummy user"} + + describe, err := handler.DescribeURN(context.Background(), testChannels[0], urn) + assert.Nil(t, err) + assert.Equal(t, data, describe) +} From 525d9a631aa82d4b821611def40a8a5b9a4658cc Mon Sep 17 00:00:00 2001 From: Robi9 Date: Tue, 19 Jul 2022 16:44:44 -0300 Subject: [PATCH 016/294] Add link preview support in WAC --- handlers/facebookapp/facebookapp.go | 32 ++++++++++++++---- handlers/facebookapp/facebookapp_test.go | 42 ++++++++++++++---------- 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index e3e2e29af..4f6b0b793 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -982,7 +982,8 @@ type wacComponent struct { } type wacText struct { - Body string `json:"body"` + Body string `json:"body"` + PreviewURL bool `json:"preview_url,omitempty"` } type wacLanguage struct { @@ -1020,7 +1021,6 @@ type wacInteractive struct { type wacMTPayload struct { MessagingProduct string `json:"messaging_product"` - PreviewURL bool `json:"preview_url"` RecipientType string `json:"recipient_type"` To string `json:"to"` Type string `json:"type"` @@ -1086,8 +1086,13 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg) } else { if i < (len(msgParts) + len(msg.Attachments()) - 1) { // this is still a msg part + text := &wacText{} payload.Type = "text" - payload.Text = &wacText{Body: msgParts[i-len(msg.Attachments())]} + if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") { + text.PreviewURL = true + } + text.Body = msgParts[i-len(msg.Attachments())] + payload.Text = text } else { if len(qrs) > 0 { payload.Type = "interactive" @@ -1140,8 +1145,13 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg) } } else { // this is still a msg part + text := &wacText{} payload.Type = "text" - payload.Text = &wacText{Body: msgParts[i-len(msg.Attachments())]} + if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") { + text.PreviewURL = true + } + text.Body = msgParts[i-len(msg.Attachments())] + payload.Text = text } } } @@ -1167,8 +1177,13 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg) } else { if i < (len(msgParts) + len(msg.Attachments()) - 1) { // this is still a msg part + text := &wacText{} payload.Type = "text" - payload.Text = &wacText{Body: msgParts[i-len(msg.Attachments())]} + if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") { + text.PreviewURL = true + } + text.Body = msgParts[i-len(msg.Attachments())] + payload.Text = text } else { if len(qrs) > 0 { payload.Type = "interactive" @@ -1222,8 +1237,13 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg) } } else { // this is still a msg part + text := &wacText{} payload.Type = "text" - payload.Text = &wacText{Body: msgParts[i-len(msg.Attachments())]} + if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") { + text.PreviewURL = true + } + text.Body = msgParts[i-len(msg.Attachments())] + payload.Text = text } } diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index aaba35fd3..f1e5324de 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -499,13 +499,13 @@ var SendTestCasesWAC = []ChannelSendTestCase{ Text: "Simple Message", URN: "whatsapp:250788123123", Path: "/12345_ID/messages", Status: "W", ExternalID: "157b5e14568e8", ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"Simple Message"}}`, + RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"Simple Message"}}`, SendPrep: setSendURL}, {Label: "Unicode Send", Text: "☺", URN: "whatsapp:250788123123", Path: "/12345_ID/messages", Status: "W", ExternalID: "157b5e14568e8", ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"☺"}}`, + RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"☺"}}`, SendPrep: setSendURL}, {Label: "Audio Send", Text: "audio caption", @@ -516,7 +516,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockedRequest{ Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"audio","audio":{"link":"https://foo.bar/audio.mp3"}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"audio","audio":{"link":"https://foo.bar/audio.mp3"}}`, }: MockedResponse{ Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, @@ -524,7 +524,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockedRequest{ Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"audio caption"}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"audio caption"}}`, }: MockedResponse{ Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, @@ -540,7 +540,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockedRequest{ Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"document","document":{"link":"https://foo.bar/document.pdf"}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"document","document":{"link":"https://foo.bar/document.pdf"}}`, }: MockedResponse{ Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, @@ -548,7 +548,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockedRequest{ Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"document caption"}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"document caption"}}`, }: MockedResponse{ Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, @@ -565,7 +565,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockedRequest{ Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, }: MockedResponse{ Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, @@ -573,7 +573,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockedRequest{ Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"document caption"}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"document caption"}}`, }: MockedResponse{ Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, @@ -589,7 +589,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockedRequest{ Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"video","video":{"link":"https://foo.bar/video.mp4"}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"video","video":{"link":"https://foo.bar/video.mp4"}}`, }: MockedResponse{ Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, @@ -597,7 +597,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockedRequest{ Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"video caption"}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"video caption"}}`, }: MockedResponse{ Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, @@ -611,7 +611,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ Status: "W", ExternalID: "157b5e14568e8", Metadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "language": "eng", "variables": ["Chef", "tomorrow"]}}`), ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 200, - RequestBody: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"template","template":{"name":"revive_issue","language":{"policy":"deterministic","code":"en"},"components":[{"type":"body","sub_type":"","index":"","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, + RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"template","template":{"name":"revive_issue","language":{"policy":"deterministic","code":"en"},"components":[{"type":"body","sub_type":"","index":"","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, SendPrep: setSendURL, }, @@ -621,7 +621,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ Status: "W", ExternalID: "157b5e14568e8", Metadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "language": "eng", "country": "US", "variables": ["Chef", "tomorrow"]}}`), ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 200, - RequestBody: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"template","template":{"name":"revive_issue","language":{"policy":"deterministic","code":"en_US"},"components":[{"type":"body","sub_type":"","index":"","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, + RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"template","template":{"name":"revive_issue","language":{"policy":"deterministic","code":"en_US"},"components":[{"type":"body","sub_type":"","index":"","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, SendPrep: setSendURL, }, {Label: "Template Invalid Language", @@ -633,13 +633,13 @@ var SendTestCasesWAC = []ChannelSendTestCase{ Text: "Interactive Button Msg", URN: "whatsapp:250788123123", QuickReplies: []string{"BUTTON1"}, Status: "W", ExternalID: "157b5e14568e8", ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, + RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, SendPrep: setSendURL}, {Label: "Interactive List Message Send", Text: "Interactive List Msg", URN: "whatsapp:250788123123", QuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4"}, Status: "W", ExternalID: "157b5e14568e8", ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, + RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, SendPrep: setSendURL}, {Label: "Interactive Button Message Send with attachment", Text: "Interactive Button Msg", URN: "whatsapp:250788123123", QuickReplies: []string{"BUTTON1"}, @@ -649,7 +649,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockedRequest{ Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, }: MockedResponse{ Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, @@ -657,7 +657,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockedRequest{ Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, }: MockedResponse{ Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, @@ -672,7 +672,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockedRequest{ Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, }: MockedResponse{ Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, @@ -680,13 +680,19 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockedRequest{ Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","preview_url":false,"recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, }: MockedResponse{ Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, SendPrep: setSendURL}, + {Label: "Link Sending", + Text: "Link Sending https://link.com", URN: "whatsapp:250788123123", Path: "/12345_ID/messages", + Status: "W", ExternalID: "157b5e14568e8", + ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, + RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"Link Sending https://link.com","preview_url":true}}`, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { From 8703796b207c276175eedb05d402b2c6cb044c2e Mon Sep 17 00:00:00 2001 From: Robi9 Date: Wed, 20 Jul 2022 11:38:47 -0300 Subject: [PATCH 017/294] Fix receiving quick replies and list replies --- handlers/facebookapp/facebookapp.go | 15 +++++++ handlers/facebookapp/facebookapp_test.go | 6 +++ .../testdata/wac/buttonReplyWAC.json | 43 +++++++++++++++++++ .../testdata/wac/listReplyWAC.json | 43 +++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 handlers/facebookapp/testdata/wac/buttonReplyWAC.json create mode 100644 handlers/facebookapp/testdata/wac/listReplyWAC.json diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index e3e2e29af..0a8d461d0 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -175,6 +175,17 @@ type moPayload struct { Text string `json:"text"` Payload string `json:"payload"` } `json:"button"` + Interactive struct { + Type string `json:"type"` + ButtonReply struct { + ID string `json:"id"` + Title string `json:"title"` + } `json:"button_reply,omitempty"` + ListReply struct { + ID string `json:"id"` + Title string `json:"title"` + } `json:"list_reply,omitempty"` + } `json:"interactive,omitempty"` } `json:"messages"` Statuses []struct { ID string `json:"id"` @@ -441,6 +452,10 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri mediaURL, err = resolveMediaURL(channel, msg.Video.ID) } else if msg.Type == "location" && msg.Location != nil { mediaURL = fmt.Sprintf("geo:%f,%f", msg.Location.Latitude, msg.Location.Longitude) + } else if msg.Type == "interactive" && msg.Interactive.Type == "button_reply" { + text = msg.Interactive.ButtonReply.Title + } else if msg.Type == "interactive" && msg.Interactive.Type == "list_reply" { + text = msg.Interactive.ListReply.Title } else { // we received a message type we do not support. courier.LogRequestError(r, channel, fmt.Errorf("unsupported message type %s", msg.Type)) diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index aaba35fd3..50b6a62f2 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -275,6 +275,12 @@ var testCasesWAC = []ChannelHandleTestCase{ MsgStatus: Sp("S"), ExternalID: Sp("external_id"), PrepRequest: addValidSignature}, {Label: "Receive Invalid Status", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/invalidStatusWAC.json")), Status: 400, Response: `"unknown status: in_orbit"`, PrepRequest: addValidSignature}, {Label: "Receive Ignore Status", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/ignoreStatusWAC.json")), Status: 200, Response: `"ignoring status: deleted"`, PrepRequest: addValidSignature}, + {Label: "Receive Valid Interactive Button Reply Message", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/buttonReplyWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + Text: Sp("Yes"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + PrepRequest: addValidSignature}, + {Label: "Receive Valid Interactive List Reply Message", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/listReplyWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + Text: Sp("Yes"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + PrepRequest: addValidSignature}, } func TestHandler(t *testing.T) { diff --git a/handlers/facebookapp/testdata/wac/buttonReplyWAC.json b/handlers/facebookapp/testdata/wac/buttonReplyWAC.json new file mode 100644 index 000000000..e44859b0d --- /dev/null +++ b/handlers/facebookapp/testdata/wac/buttonReplyWAC.json @@ -0,0 +1,43 @@ +{ + "object": "whatsapp_business_account", + "entry": [ + { + "id": "8856996819413533", + "changes": [ + { + "value": { + "messaging_product": "whatsapp", + "metadata": { + "display_phone_number": "+250 788 123 200", + "phone_number_id": "12345" + }, + "contacts": [ + { + "profile": { + "name": "Kerry Fisher" + }, + "wa_id": "5678" + } + ], + "messages": [ + { + "from": "5678", + "id": "external_id", + "interactive": { + "type": "button_reply", + "button_reply": { + "id": "id_button_reply", + "title": "Yes" + } + }, + "timestamp": "1454119029", + "type": "interactive" + } + ] + }, + "field": "messages" + } + ] + } + ] +} \ No newline at end of file diff --git a/handlers/facebookapp/testdata/wac/listReplyWAC.json b/handlers/facebookapp/testdata/wac/listReplyWAC.json new file mode 100644 index 000000000..1f3d2981c --- /dev/null +++ b/handlers/facebookapp/testdata/wac/listReplyWAC.json @@ -0,0 +1,43 @@ +{ + "object": "whatsapp_business_account", + "entry": [ + { + "id": "8856996819413533", + "changes": [ + { + "value": { + "messaging_product": "whatsapp", + "metadata": { + "display_phone_number": "+250 788 123 200", + "phone_number_id": "12345" + }, + "contacts": [ + { + "profile": { + "name": "Kerry Fisher" + }, + "wa_id": "5678" + } + ], + "messages": [ + { + "from": "5678", + "id": "external_id", + "interactive": { + "type": "list_reply", + "list_reply": { + "id": "id_list_reply", + "title": "Yes" + } + }, + "timestamp": "1454119029", + "type": "interactive" + } + ] + }, + "field": "messages" + } + ] + } + ] +} \ No newline at end of file From cabd84d6221298693f423b7998e1b1325bdcf4a1 Mon Sep 17 00:00:00 2001 From: Robi9 Date: Wed, 20 Jul 2022 14:55:59 -0300 Subject: [PATCH 018/294] Fix receiving attachments in WAC --- backends/rapidpro/msg.go | 5 +++++ handlers/facebookapp/facebookapp.go | 15 ++++++++------- handlers/facebookapp/facebookapp_test.go | 2 +- handlers/test.go | 1 + 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index 92460a9a5..b16bd2fd3 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -247,6 +247,11 @@ func downloadMediaToS3(ctx context.Context, b *backend, channel courier.Channel, } } + // to allow download media from wac when receive media message + if channel.ChannelType() == "WAC" { + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", b.config.WhatsappAdminSystemUserToken)) + } + resp, err := utils.GetHTTPClient().Do(req) if err != nil { return "", err diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index e3e2e29af..223d66543 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -319,8 +319,7 @@ func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w return nil, err } -func resolveMediaURL(channel courier.Channel, mediaID string) (string, error) { - token := channel.StringConfigForKey(courier.ConfigAuthToken, "") +func resolveMediaURL(channel courier.Channel, mediaID string, token string) (string, error) { if token == "" { return "", fmt.Errorf("missing token for WA channel") } @@ -390,6 +389,8 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri // the list of data we will return in our response data := make([]interface{}, 0, 2) + token := h.Server().Config().WhatsappAdminSystemUserToken + var contactNames = make(map[string]string) // for each entry @@ -424,21 +425,21 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri text = msg.Text.Body } else if msg.Type == "audio" && msg.Audio != nil { text = msg.Audio.Caption - mediaURL, err = resolveMediaURL(channel, msg.Audio.ID) + mediaURL, err = resolveMediaURL(channel, msg.Audio.ID, token) } else if msg.Type == "voice" && msg.Voice != nil { text = msg.Voice.Caption - mediaURL, err = resolveMediaURL(channel, msg.Voice.ID) + mediaURL, err = resolveMediaURL(channel, msg.Voice.ID, token) } else if msg.Type == "button" && msg.Button != nil { text = msg.Button.Text } else if msg.Type == "document" && msg.Document != nil { text = msg.Document.Caption - mediaURL, err = resolveMediaURL(channel, msg.Document.ID) + mediaURL, err = resolveMediaURL(channel, msg.Document.ID, token) } else if msg.Type == "image" && msg.Image != nil { text = msg.Image.Caption - mediaURL, err = resolveMediaURL(channel, msg.Image.ID) + mediaURL, err = resolveMediaURL(channel, msg.Image.ID, token) } else if msg.Type == "video" && msg.Video != nil { text = msg.Video.Caption - mediaURL, err = resolveMediaURL(channel, msg.Video.ID) + mediaURL, err = resolveMediaURL(channel, msg.Video.ID, token) } else if msg.Type == "location" && msg.Location != nil { mediaURL = fmt.Sprintf("geo:%f,%f", msg.Location.Latitude, msg.Location.Longitude) } else { diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index aaba35fd3..b50103f18 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -283,7 +283,7 @@ func TestHandler(t *testing.T) { defer r.Body.Close() // invalid auth token - if accessToken != "Bearer a123" { + if accessToken != "Bearer a123" && accessToken != "Bearer wac_admin_system_user_token" { fmt.Printf("Access token: %s\n", accessToken) http.Error(w, "invalid auth token", 403) return diff --git a/handlers/test.go b/handlers/test.go index 03550f68e..d420c5990 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -202,6 +202,7 @@ func newServer(backend courier.Backend) courier.Server { config := courier.NewConfig() config.FacebookWebhookSecret = "fb_webhook_secret" config.FacebookApplicationSecret = "fb_app_secret" + config.WhatsappAdminSystemUserToken = "wac_admin_system_user_token" return courier.NewServerWithLogger(config, backend, logger) From 95aec4f8cceb7590daacbbd4063d5aa2d2f065d2 Mon Sep 17 00:00:00 2001 From: Robi9 Date: Thu, 21 Jul 2022 10:20:16 -0300 Subject: [PATCH 019/294] Fix preview_url parameter to be explicit --- handlers/facebookapp/facebookapp.go | 6 +++++- handlers/facebookapp/facebookapp_test.go | 12 ++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 4f6b0b793..047f52b3a 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -983,7 +983,7 @@ type wacComponent struct { type wacText struct { Body string `json:"body"` - PreviewURL bool `json:"preview_url,omitempty"` + PreviewURL bool `json:"preview_url"` } type wacLanguage struct { @@ -1088,6 +1088,7 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg) // this is still a msg part text := &wacText{} payload.Type = "text" + text.PreviewURL = false if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") { text.PreviewURL = true } @@ -1147,6 +1148,7 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg) // this is still a msg part text := &wacText{} payload.Type = "text" + text.PreviewURL = false if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") { text.PreviewURL = true } @@ -1179,6 +1181,7 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg) // this is still a msg part text := &wacText{} payload.Type = "text" + text.PreviewURL = false if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") { text.PreviewURL = true } @@ -1239,6 +1242,7 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg) // this is still a msg part text := &wacText{} payload.Type = "text" + text.PreviewURL = false if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") { text.PreviewURL = true } diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index f1e5324de..d025961e3 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -499,13 +499,13 @@ var SendTestCasesWAC = []ChannelSendTestCase{ Text: "Simple Message", URN: "whatsapp:250788123123", Path: "/12345_ID/messages", Status: "W", ExternalID: "157b5e14568e8", ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"Simple Message"}}`, + RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"Simple Message","preview_url":false}}`, SendPrep: setSendURL}, {Label: "Unicode Send", Text: "☺", URN: "whatsapp:250788123123", Path: "/12345_ID/messages", Status: "W", ExternalID: "157b5e14568e8", ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"☺"}}`, + RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"☺","preview_url":false}}`, SendPrep: setSendURL}, {Label: "Audio Send", Text: "audio caption", @@ -524,7 +524,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockedRequest{ Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"audio caption"}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"audio caption","preview_url":false}}`, }: MockedResponse{ Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, @@ -548,7 +548,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockedRequest{ Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"document caption"}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"document caption","preview_url":false}}`, }: MockedResponse{ Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, @@ -573,7 +573,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockedRequest{ Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"document caption"}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"document caption","preview_url":false}}`, }: MockedResponse{ Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, @@ -597,7 +597,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockedRequest{ Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"video caption"}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"video caption","preview_url":false}}`, }: MockedResponse{ Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, From f1bbf324150ddaf09a7f70212423801152e0a713 Mon Sep 17 00:00:00 2001 From: Robi9 Date: Thu, 21 Jul 2022 10:40:31 -0300 Subject: [PATCH 020/294] Remove unused parameter --- handlers/facebookapp/facebookapp.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 223d66543..99fe641d3 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -319,7 +319,7 @@ func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w return nil, err } -func resolveMediaURL(channel courier.Channel, mediaID string, token string) (string, error) { +func resolveMediaURL(mediaID string, token string) (string, error) { if token == "" { return "", fmt.Errorf("missing token for WA channel") } @@ -425,21 +425,21 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri text = msg.Text.Body } else if msg.Type == "audio" && msg.Audio != nil { text = msg.Audio.Caption - mediaURL, err = resolveMediaURL(channel, msg.Audio.ID, token) + mediaURL, err = resolveMediaURL(msg.Audio.ID, token) } else if msg.Type == "voice" && msg.Voice != nil { text = msg.Voice.Caption - mediaURL, err = resolveMediaURL(channel, msg.Voice.ID, token) + mediaURL, err = resolveMediaURL(msg.Voice.ID, token) } else if msg.Type == "button" && msg.Button != nil { text = msg.Button.Text } else if msg.Type == "document" && msg.Document != nil { text = msg.Document.Caption - mediaURL, err = resolveMediaURL(channel, msg.Document.ID, token) + mediaURL, err = resolveMediaURL(msg.Document.ID, token) } else if msg.Type == "image" && msg.Image != nil { text = msg.Image.Caption - mediaURL, err = resolveMediaURL(channel, msg.Image.ID, token) + mediaURL, err = resolveMediaURL(msg.Image.ID, token) } else if msg.Type == "video" && msg.Video != nil { text = msg.Video.Caption - mediaURL, err = resolveMediaURL(channel, msg.Video.ID, token) + mediaURL, err = resolveMediaURL(msg.Video.ID, token) } else if msg.Type == "location" && msg.Location != nil { mediaURL = fmt.Sprintf("geo:%f,%f", msg.Location.Latitude, msg.Location.Longitude) } else { From 970857b10bddbbeb7251945935524ca7403d23b3 Mon Sep 17 00:00:00 2001 From: Robi9 Date: Thu, 21 Jul 2022 11:15:52 -0300 Subject: [PATCH 021/294] Add false to PreviewURL --- handlers/facebookapp/facebookapp.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 047f52b3a..43f89b88e 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -1086,9 +1086,8 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg) } else { if i < (len(msgParts) + len(msg.Attachments()) - 1) { // this is still a msg part - text := &wacText{} + text := &wacText{PreviewURL: false} payload.Type = "text" - text.PreviewURL = false if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") { text.PreviewURL = true } @@ -1146,9 +1145,8 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg) } } else { // this is still a msg part - text := &wacText{} + text := &wacText{PreviewURL: false} payload.Type = "text" - text.PreviewURL = false if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") { text.PreviewURL = true } @@ -1179,9 +1177,8 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg) } else { if i < (len(msgParts) + len(msg.Attachments()) - 1) { // this is still a msg part - text := &wacText{} + text := &wacText{PreviewURL: false} payload.Type = "text" - text.PreviewURL = false if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") { text.PreviewURL = true } @@ -1240,9 +1237,8 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg) } } else { // this is still a msg part - text := &wacText{} + text := &wacText{PreviewURL: false} payload.Type = "text" - text.PreviewURL = false if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") { text.PreviewURL = true } From 8c2b0e87db4f9181ac7f284abc2b5b8334a120a5 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 21 Jul 2022 14:24:42 -0500 Subject: [PATCH 022/294] Update CHANGELOG.md for v7.5.0 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0c898ff8..eeafc1027 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.0 +---------- + * Fix receiving quick replies and list replies in WAC + * Add link preview support in WAC + v7.4.0 ---------- * Update README From ef6acb9b6e576c3bca74aabc3c22880aac3e3f0b Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Fri, 22 Jul 2022 13:47:33 +0200 Subject: [PATCH 023/294] Support Quick replies for LINE channels --- handlers/line/line.go | 43 +++++++++++++++++++++++++++++++++----- handlers/line/line_test.go | 18 +++++++++++++--- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/handlers/line/line.go b/handlers/line/line.go index 3f5645cd4..ea0b3e935 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -181,8 +181,22 @@ func calculateSignature(secret string, r *http.Request) ([]byte, error) { } type mtTextMsg struct { - Type string `json:"type"` - Text string `json:"text"` + Type string `json:"type"` + Text string `json:"text"` + QuickReply *mtQuickReply `json:"quickReply,omitempty"` +} + +type mtQuickReply struct { + Items []QuickReplyItem `json:"items"` +} + +type QuickReplyItem struct { + Type string `json:"type"` + Action struct { + Type string `json:"type"` + Label string `json:"label"` + Text string `json:"text"` + } `json:"action"` } type mtImageMsg struct { @@ -208,10 +222,29 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat // all msg parts in JSON var jsonMsgs []string parts := handlers.SplitMsgByChannel(msg.Channel(), msg.Text(), maxMsgLength) + qrs := msg.QuickReplies() + // fill all msg parts with text parts - for _, part := range parts { - if jsonMsg, err := json.Marshal(mtTextMsg{Type: "text", Text: part}); err == nil { - jsonMsgs = append(jsonMsgs, string(jsonMsg)) + for i, part := range parts { + if i < (len(parts) - 1) { + if jsonMsg, err := json.Marshal(mtTextMsg{Type: "text", Text: part}); err == nil { + jsonMsgs = append(jsonMsgs, string(jsonMsg)) + } + } else { + mtTextMsg := mtTextMsg{Type: "text", Text: part} + items := make([]QuickReplyItem, len(qrs)) + for j, qr := range qrs { + items[j] = QuickReplyItem{Type: "action"} + items[j].Action.Type = "message" + items[j].Action.Label = qr + items[j].Action.Text = qr + } + if len(items) > 0 { + mtTextMsg.QuickReply = &mtQuickReply{Items: items} + } + if jsonMsg, err := json.Marshal(mtTextMsg); err == nil { + jsonMsgs = append(jsonMsgs, string(jsonMsg)) + } } } // fill all msg parts with attachment parts diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index e7a50a91e..f525fc3bd 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -171,7 +171,7 @@ func BenchmarkHandler(b *testing.B) { // setSendURL takes care of setting the send_url to our test server host func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { replySendURL = s.URL + "/v2/bot/message/reply" - pushSendURL = s.URL + "/v2/bot/message/push" + pushSendURL = s.URL + "/v2/bot/message/push" } const tooLongMsg = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas convallis augue vel placerat congue. @@ -265,6 +265,18 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, RequestBody: `{"replyToken":"nHuyWiB7yP5Zw52FIkcQobQuGDXCTA","messages":[{"type":"text","text":"Simple Message"}]}`, SendPrep: setSendURL}, + {Label: "Quick Reply", + Text: "Are you happy?", URN: "line:uabcdefghij", + QuickReplies: []string{"Yes", "No"}, + Status: "W", + ResponseBody: `{}`, ResponseStatus: 200, + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "Bearer AccessToken", + }, + RequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Are you happy?","quickReply":{"items":[{"type":"action","action":{"type":"message","label":"Yes","text":"Yes"}},{"type":"action","action":{"type":"message","label":"No","text":"No"}}]}}]}`, + SendPrep: setSendURL}, {Label: "Send Push Message If Invalid Reply", Text: "Simple Message", URN: "line:uabcdefghij", ResponseToExternalID: "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA", Status: "W", @@ -275,7 +287,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ BodyContains: `{"replyToken":"nHuyWiB7yP5Zw52FIkcQobQuGDXCTA","messages":[{"type":"text","text":"Simple Message"}]}`, }: { Status: 400, - Body: `{"message":"Invalid reply token"}`, + Body: `{"message":"Invalid reply token"}`, }, MockedRequest{ Method: "POST", @@ -283,7 +295,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ BodyContains: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Simple Message"}]}`, }: { Status: 200, - Body: `{}`, + Body: `{}`, }, }, SendPrep: setSendURL}, From b4b8f5db0fbd3c9365b5507d29f40a9b220d1248 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 22 Jul 2022 10:11:56 -0500 Subject: [PATCH 024/294] Update CHANGELOG.md for v7.5.1 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eeafc1027..e34e177f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.1 +---------- + * Support Quick replies for LINE channels + * Slack channel support + v7.5.0 ---------- * Fix receiving quick replies and list replies in WAC From 4702d882030c0e71d5658cd827f2afbaa1dde657 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Fri, 22 Jul 2022 17:15:15 +0200 Subject: [PATCH 025/294] Support receiving LINE attachments --- handlers/line/line.go | 65 ++++++++++++++-- handlers/line/line_test.go | 150 ++++++++++++++++++++++++++++++++++++- 2 files changed, 209 insertions(+), 6 deletions(-) diff --git a/handlers/line/line.go b/handlers/line/line.go index ea0b3e935..924cb3ec2 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -10,6 +10,7 @@ import ( "fmt" "io/ioutil" "net/http" + "net/url" "strings" "time" @@ -26,6 +27,7 @@ import ( var ( replySendURL = "https://api.line.me/v2/bot/message/reply" pushSendURL = "https://api.line.me/v2/bot/message/push" + mediaDataURL = "https://api-data.line.me/v2/bot/message" maxMsgLength = 2000 maxMsgSend = 5 @@ -88,9 +90,17 @@ type moPayload struct { UserID string `json:"userId"` } `json:"source"` Message struct { - ID string `json:"id"` - Type string `json:"type"` - Text string `json:"text"` + ID string `json:"id"` + Type string `json:"type"` + Text string `json:"text"` + Title string `json:"title"` + Address string `json:"address"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + ContentProvider struct { + Type string `json:"type"` + OriginalContentURL string `json:"originalContentUrl"` + } `json:"contentProvider"` } `json:"message"` } `json:"events"` } @@ -111,7 +121,29 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msgs := []courier.Msg{} for _, lineEvent := range payload.Events { - if lineEvent.ReplyToken == "" || (lineEvent.Source.Type == "" && lineEvent.Source.UserID == "") || (lineEvent.Message.Type == "" && lineEvent.Message.ID == "" && lineEvent.Message.Text == "") || lineEvent.Message.Type != "text" { + if lineEvent.ReplyToken == "" || (lineEvent.Source.Type == "" && lineEvent.Source.UserID == "") || (lineEvent.Message.Type == "" && lineEvent.Message.ID == "") { + continue + } + + text := "" + mediaURL := "" + + lineEventMsgType := lineEvent.Message.Type + + if lineEventMsgType == "text" { + text = lineEvent.Message.Text + + } else if lineEventMsgType == "audio" || lineEventMsgType == "video" || lineEventMsgType == "image" || lineEventMsgType == "file" { + if lineEvent.Message.ContentProvider.Type == "line" || lineEventMsgType == "file" { + mediaURL = buildMediaURL(lineEvent.Message.ID) + } else if lineEvent.Message.ContentProvider.Type == "external" { + mediaURL = lineEvent.Message.ContentProvider.OriginalContentURL + } + + } else if lineEventMsgType == "location" { + mediaURL = fmt.Sprintf("geo:%f,%f", lineEvent.Message.Latitude, lineEvent.Message.Longitude) + text = lineEvent.Message.Title + } else { continue } @@ -123,7 +155,12 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } - msg := h.Backend().NewIncomingMsg(channel, urn, lineEvent.Message.Text).WithExternalID(lineEvent.ReplyToken).WithReceivedOn(date) + msg := h.Backend().NewIncomingMsg(channel, urn, text).WithExternalID(lineEvent.ReplyToken).WithReceivedOn(date) + + if mediaURL != "" { + msg.WithAttachment(mediaURL) + } + msgs = append(msgs, msg) } @@ -135,6 +172,24 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } +func buildMediaURL(mediaID string) string { + mediaURL, _ := url.Parse(fmt.Sprintf("%s/%s/content", mediaDataURL, mediaID)) + return mediaURL.String() +} + +// BuildDownloadMediaRequest to download media for message attachment with Bearer token set +func (h *handler) BuildDownloadMediaRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { + token := channel.StringConfigForKey(courier.ConfigAuthToken, "") + if token == "" { + return nil, fmt.Errorf("missing token for LN channel") + } + + // set the access token as the authorization header + req, _ := http.NewRequest(http.MethodGet, attachmentURL, nil) + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) + return req, nil +} + func (h *handler) validateSignature(channel courier.Channel, r *http.Request) error { actual := r.Header.Get(signatureHeader) if actual == "" { diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index f525fc3bd..f9c814edf 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -1,6 +1,7 @@ package line import ( + "context" "net/http" "net/http/httptest" "testing" @@ -8,6 +9,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/stretchr/testify/assert" ) var ( @@ -110,6 +112,125 @@ var receiveValidMessageLast = ` }] }` +var receiveValidImageMessage = ` +{ + "events": [{ + "replyToken": "abcdefghij", + "type": "message", + "timestamp": 1459991487970, + "source": { + "type": "user", + "userId": "uabcdefghij" + }, + "message": { + "id": "100001", + "type": "image", + "contentProvider": { + "type": "line" + } + } + }] +}` + +var receiveValidVideoMessage = ` +{ + "events": [{ + "replyToken": "abcdefghij", + "type": "message", + "timestamp": 1459991487970, + "source": { + "type": "user", + "userId": "uabcdefghij" + }, + "message": { + "id": "100001", + "type": "video", + "contentProvider": { + "type": "line" + } + } + }] +}` + +var receiveValidVideoExternalMessage = ` +{ + "events": [{ + "replyToken": "abcdefghij", + "type": "message", + "timestamp": 1459991487970, + "source": { + "type": "user", + "userId": "uabcdefghij" + }, + "message": { + "id": "100001", + "type": "video", + "contentProvider": { + "type": "external", + "originalContentUrl": "https://example.com/original.mp4" + } + } + }] +}` + +var receiveValidAudioMessage = ` +{ + "events": [{ + "replyToken": "abcdefghij", + "type": "message", + "timestamp": 1459991487970, + "source": { + "type": "user", + "userId": "uabcdefghij" + }, + "message": { + "id": "100001", + "type": "audio", + "contentProvider": { + "type": "line" + } + } + }] +}` + +var receiveValidFileMessage = ` +{ + "events": [{ + "replyToken": "abcdefghij", + "type": "message", + "timestamp": 1459991487970, + "source": { + "type": "user", + "userId": "uabcdefghij" + }, + "message": { + "id": "100001", + "type": "audio" + } + }] +}` + +var receiveValidLocationMessage = ` +{ + "events": [{ + "replyToken": "abcdefghij", + "type": "message", + "timestamp": 1459991487970, + "source": { + "type": "user", + "userId": "uabcdefghij" + }, + "message": { + "id": "100001", + "type": "location", + "title": "my location", + "address": "Japan, 〒160-0004 Tokyo, Shinjuku City, Yotsuya, 1-chōme-6-1", + "latitude": 35.687574, + "longitude": 139.72922 + } + }] +}` + var missingMessage = `{ "events": [{ "replyToken": "abcdefghij", @@ -129,7 +250,8 @@ var noEvent = `{ var testChannels = []courier.Channel{ courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "LN", "2020", "US", map[string]interface{}{ - "secret": "Secret", + "secret": "Secret", + "auth_token": "the-auth-token", }), } @@ -140,6 +262,23 @@ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessageLast, Status: 200, Response: "Accepted", Text: Sp("Last event"), URN: Sp("line:uabcdefghij"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, + + {Label: "Receive Valid Image Message", URL: receiveURL, Data: receiveValidImageMessage, Status: 200, Response: "Accepted", + Text: Sp(""), Attachment: Sp("https://api-data.line.me/v2/bot/message/100001/content"), URN: Sp("line:uabcdefghij"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + PrepRequest: addValidSignature}, + {Label: "Receive Valid Video Message", URL: receiveURL, Data: receiveValidVideoMessage, Status: 200, Response: "Accepted", + Text: Sp(""), Attachment: Sp("https://api-data.line.me/v2/bot/message/100001/content"), URN: Sp("line:uabcdefghij"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + PrepRequest: addValidSignature}, + {Label: "Receive Valid Video External Message", URL: receiveURL, Data: receiveValidVideoExternalMessage, Status: 200, Response: "Accepted", + Text: Sp(""), Attachment: Sp("https://example.com/original.mp4"), URN: Sp("line:uabcdefghij"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + PrepRequest: addValidSignature}, + {Label: "Receive Valid Audio Message", URL: receiveURL, Data: receiveValidAudioMessage, Status: 200, Response: "Accepted", + Text: Sp(""), Attachment: Sp("https://api-data.line.me/v2/bot/message/100001/content"), URN: Sp("line:uabcdefghij"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + PrepRequest: addValidSignature}, + {Label: "Receive Valid Location Message", URL: receiveURL, Data: receiveValidLocationMessage, Status: 200, Response: "Accepted", + Text: Sp("my location"), Attachment: Sp("geo:35.687574,139.729220"), URN: Sp("line:uabcdefghij"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + PrepRequest: addValidSignature}, + {Label: "Missing message", URL: receiveURL, Data: missingMessage, Status: 200, Response: "ignoring request, no message", PrepRequest: addValidSignature}, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, Status: 400, Response: "invalid line id", @@ -317,3 +456,12 @@ func TestSending(t *testing.T) { RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) } + +func TestBuildMediaRequest(t *testing.T) { + mb := courier.NewMockBackend() + + lnHandler := &handler{NewBaseHandler(courier.ChannelType("LN"), "Line")} + req, _ := lnHandler.BuildDownloadMediaRequest(context.Background(), mb, testChannels[0], "https://example.org/v1/media/41") + assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) + assert.Equal(t, "Bearer the-auth-token", req.Header.Get("Authorization")) +} From 3c5b08c9e7029028d1b59dacc45f29ebdb02f325 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 22 Jul 2022 10:28:18 -0500 Subject: [PATCH 026/294] Update CHANGELOG.md for v7.5.2 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e34e177f2..240a294aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.2 +---------- + * Support receiving LINE attachments + v7.5.1 ---------- * Support Quick replies for LINE channels From 013b06eb14cfad32e998814b90ea5c530606c9ec Mon Sep 17 00:00:00 2001 From: Robi9 Date: Fri, 22 Jul 2022 17:03:01 -0300 Subject: [PATCH 027/294] Add BuildDownloadMediaRequest to WAC --- backends/rapidpro/msg.go | 5 ---- handlers/facebookapp/facebookapp.go | 16 +++++++++++++ handlers/facebookapp/facebookapp_test.go | 29 ++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index b16bd2fd3..92460a9a5 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -247,11 +247,6 @@ func downloadMediaToS3(ctx context.Context, b *backend, channel courier.Channel, } } - // to allow download media from wac when receive media message - if channel.ChannelType() == "WAC" { - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", b.config.WhatsappAdminSystemUserToken)) - } - resp, err := utils.GetHTTPClient().Do(req) if err != nil { return "", err diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 99fe641d3..0b83a9cd3 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -1395,6 +1395,22 @@ func (h *handler) getTemplate(msg courier.Msg) (*MsgTemplating, error) { return templating, err } +// BuildDownloadMediaRequest to download media for message attachment with Bearer token set +func (h *handler) BuildDownloadMediaRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { + token := h.Server().Config().WhatsappAdminSystemUserToken + if token == "" { + return nil, fmt.Errorf("missing token for WAC channel") + } + + req, _ := http.NewRequest(http.MethodGet, attachmentURL, nil) + + // set the access token as the authorization header for WAC + if channel.ChannelType() == "WAC" { + req.Header.Set("Authorization", "Bearer "+token) + } + return req, nil +} + type TemplateMetadata struct { Templating *MsgTemplating `json:"templating"` } diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index b50103f18..c8e8f3784 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -721,3 +721,32 @@ func TestSigning(t *testing.T) { assert.Equal(t, tc.Signature, sig, "%d: mismatched signature", i) } } + +func newServer(backend courier.Backend) courier.Server { + config := courier.NewConfig() + config.WhatsappAdminSystemUserToken = "wac_admin_system_user_token" + return courier.NewServer(config, backend) +} + +func TestBuildMediaRequest(t *testing.T) { + mb := courier.NewMockBackend() + s := newServer(mb) + wacHandler := &handler{NewBaseHandlerWithParams(courier.ChannelType("WAC"), "WhatsApp Cloud", false)} + wacHandler.Initialize(s) + req, _ := wacHandler.BuildDownloadMediaRequest(context.Background(), mb, testChannelsWAC[0], "https://example.org/v1/media/41") + assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) + assert.Equal(t, "Bearer wac_admin_system_user_token", req.Header.Get("Authorization")) + + fbaHandler := &handler{NewBaseHandlerWithParams(courier.ChannelType("FBA"), "Facebook", false)} + fbaHandler.Initialize(s) + req, _ = fbaHandler.BuildDownloadMediaRequest(context.Background(), mb, testChannelsFBA[0], "https://example.org/v1/media/41") + assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) + assert.Equal(t, http.Header{}, req.Header) + + igHandler := &handler{NewBaseHandlerWithParams(courier.ChannelType("IG"), "Instagram", false)} + igHandler.Initialize(s) + req, _ = igHandler.BuildDownloadMediaRequest(context.Background(), mb, testChannelsFBA[0], "https://example.org/v1/media/41") + assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) + assert.Equal(t, http.Header{}, req.Header) + +} From 32091394ab89e9a31bb277c82417cbca7de8f536 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 25 Jul 2022 09:28:50 -0500 Subject: [PATCH 028/294] Update CHANGELOG.md for v7.5.3 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 240a294aa..b3c81085f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.3 +---------- + * Fix receiving attachments in WAC + v7.5.2 ---------- * Support receiving LINE attachments From 4fb308a3f4ee07ab00e41db0bc6aabbb057da25d Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 1 Aug 2022 18:31:07 -0500 Subject: [PATCH 029/294] Add support for resolving media (WIP) --- backend.go | 14 ++++++++++ backends/rapidpro/backend.go | 46 +++++++++++++++++++++++++++++-- backends/rapidpro/media.go | 53 ++++++++++++++++++++++++++++++++++++ config.go | 5 +++- test.go | 8 ++++++ 5 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 backends/rapidpro/media.go diff --git a/backend.go b/backend.go index 9a740e7ec..8766b104f 100644 --- a/backend.go +++ b/backend.go @@ -7,6 +7,7 @@ import ( "github.com/gomodule/redigo/redis" "github.com/nyaruka/gocommon/urns" + "github.com/nyaruka/gocommon/uuids" ) // BackendConstructorFunc defines a function to create a particular backend type @@ -88,6 +89,8 @@ type Backend interface { // Mark a external ID as seen for a period WriteExternalIDSeen(Msg) + ResolveMedia(context.Context, string) (Media, error) + // Health returns a string describing any health problems the backend has, or empty string if all is well Health() string @@ -101,6 +104,17 @@ type Backend interface { RedisPool() *redis.Pool } +// Media is a resolved media object that can be used as a message attachment +type Media interface { + UUID() uuids.UUID + ContentType() string + URL() string + Alternates() []Media + Width() int + Height() int + Duration() int +} + // NewBackend creates the type of backend passed in func NewBackend(config *Config) (Backend, error) { backendFunc, found := registeredBackends[strings.ToLower(config.Backend)] diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 62c83809f..5de1ea91e 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -8,6 +8,7 @@ import ( "fmt" "net/url" "path" + "regexp" "strings" "sync" "time" @@ -22,6 +23,7 @@ import ( "github.com/nyaruka/gocommon/dbutil" "github.com/nyaruka/gocommon/storage" "github.com/nyaruka/gocommon/urns" + "github.com/nyaruka/gocommon/uuids" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -403,6 +405,46 @@ func (b *backend) WriteExternalIDSeen(msg courier.Msg) { writeExternalIDSeen(b, msg) } +var uuidRegex = regexp.MustCompile(`[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`) + +// ResolveMedia resolves the passed in attachment (content_type:url) to a media object +func (b *backend) ResolveMedia(ctx context.Context, a string) (courier.Media, error) { + // split into content-type and URL + parts := strings.SplitN(a, ":", 2) + var contentType, mediaUrl string + if len(parts) < 2 { + contentType, mediaUrl = "", parts[0] + } else { + contentType, mediaUrl = parts[0], parts[1] + } + + // if we can't parse the URL or the hostname isn't our media domain, return as is + u, err := url.Parse(mediaUrl) + if err != nil || u.Hostname() != b.config.MediaDomain { + return &Media{URL_: mediaUrl, ContentType_: contentType}, nil + } + + // likewise if path doesn't contain a UUID, return as is + mediaUUID := uuidRegex.FindString(u.Path) + if mediaUUID == "" { + return &Media{URL_: mediaUrl, ContentType_: contentType}, nil + } + + // TODO: lock and cache + + media, err := lookupMediaFromUUID(ctx, b.db, uuids.UUID(mediaUUID)) + if err != nil { + return nil, errors.Wrap(err, "error looking up media") + } + + // if we didn't find a media record or the one we found doesn't match the URL, return as is + if media == nil || media.URL() != mediaUrl { + return &Media{URL_: mediaUrl, ContentType_: contentType}, nil + } + + return media, nil +} + // Health returns the health of this backend as a string, returning "" if all is well func (b *backend) Health() string { // test redis @@ -782,9 +824,9 @@ func (b *backend) RedisPool() *redis.Pool { } // NewBackend creates a new RapidPro backend -func newBackend(config *courier.Config) courier.Backend { +func newBackend(cfg *courier.Config) courier.Backend { return &backend{ - config: config, + config: cfg, stopChan: make(chan bool), waitGroup: &sync.WaitGroup{}, diff --git a/backends/rapidpro/media.go b/backends/rapidpro/media.go new file mode 100644 index 000000000..d84d2acad --- /dev/null +++ b/backends/rapidpro/media.go @@ -0,0 +1,53 @@ +package rapidpro + +import ( + "context" + "database/sql" + + "github.com/jmoiron/sqlx" + "github.com/nyaruka/courier" + "github.com/nyaruka/gocommon/uuids" +) + +type Media struct { + UUID_ uuids.UUID `db:"uuid"` + ContentType_ string `db:"content_type"` + URL_ string `db:"url"` + Width_ int `db:"width"` + Height_ int `db:"height"` + Duration_ int `db:"duration"` + + alternates []courier.Media +} + +func (m *Media) UUID() uuids.UUID { return m.UUID_ } +func (m *Media) ContentType() string { return m.ContentType_ } +func (m *Media) URL() string { return m.URL_ } +func (m *Media) Width() int { return m.Width_ } +func (m *Media) Height() int { return m.Height_ } +func (m *Media) Duration() int { return m.Duration_ } +func (m *Media) Alternates() []courier.Media { return m.alternates } + +var _ courier.Media = &Media{} + +var sqlLookupMediaFromUUID = ` +SELECT m.uuid, m.content_type, m.url, m.width, m.height, m.duration +FROM msgs_media m +INNER JOIN msgs_media m0 ON m0.id = m.id OR m0.id = m.original_id +WHERE m0.uuid = $1 +ORDER BY m.created_on` + +func lookupMediaFromUUID(ctx context.Context, db *sqlx.DB, uuid uuids.UUID) (*Media, error) { + var records []*Media + err := db.SelectContext(ctx, &records, sqlLookupMediaFromUUID, uuid) + if err == sql.ErrNoRows { + return nil, nil + } + + media, alternates := records[0], records[1:] + media.alternates = make([]courier.Media, len(alternates)) + for i, alt := range alternates { + media.alternates[i] = alt + } + return media, nil +} diff --git a/config.go b/config.go index fb9d59a5b..2318bb552 100644 --- a/config.go +++ b/config.go @@ -1,6 +1,8 @@ package courier -import "github.com/nyaruka/ezconf" +import ( + "github.com/nyaruka/ezconf" +) // Config is our top level configuration object type Config struct { @@ -20,6 +22,7 @@ type Config struct { S3ForcePathStyle bool `help:"whether we force S3 path style. Should generally need to default to False unless you're hosting an S3 compatible service"` AWSAccessKeyID string `help:"the access key id to use when authenticating S3"` AWSSecretAccessKey string `help:"the secret access key id to use when authenticating S3"` + MediaDomain string `help:"the domain on which we'll try to resolve media URLs"` FacebookApplicationSecret string `help:"the Facebook app secret"` FacebookWebhookSecret string `help:"the secret for Facebook webhook URL verification"` MaxWorkers int `help:"the maximum number of go routines that will be used for sending (set to 0 to disable sending)"` diff --git a/test.go b/test.go index 86240b5df..f7c1ab497 100644 --- a/test.go +++ b/test.go @@ -28,6 +28,7 @@ type MockBackend struct { channels map[ChannelUUID]Channel channelsByAddress map[ChannelAddress]Channel contacts map[urns.URN]Contact + media map[string]Media queueMsgs []Msg errorOnQueue bool @@ -72,6 +73,7 @@ func NewMockBackend() *MockBackend { channels: make(map[ChannelUUID]Channel), channelsByAddress: make(map[ChannelAddress]Channel), contacts: make(map[urns.URN]Contact), + media: make(map[string]Media), sentMsgs: make(map[MsgID]bool), redisPool: redisPool, } @@ -355,6 +357,12 @@ func (mb *MockBackend) WriteExternalIDSeen(msg Msg) { mb.seenExternalIDs = append(mb.seenExternalIDs, msg.ExternalID()) } +// ResolveMedia resolves the passed in media URL to a media object +func (mb *MockBackend) ResolveMedia(ctx context.Context, a string) (Media, error) { + // TODO: implement + return nil, nil +} + // Health gives a string representing our health, empty for our mock func (mb *MockBackend) Health() string { return "" From a7379635bc3df2c3796f31e9a83e99f8e49c3a8b Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 2 Aug 2022 10:03:19 -0500 Subject: [PATCH 030/294] Update deps and fix incorrect errors import in some handler packages --- go.mod | 48 +++++++------- go.sum | 121 +++++++++++++++++----------------- handlers/telegram/telegram.go | 2 +- handlers/vk/vk.go | 2 +- 4 files changed, 85 insertions(+), 88 deletions(-) diff --git a/go.mod b/go.mod index 61456e6f8..a5d72b611 100644 --- a/go.mod +++ b/go.mod @@ -3,55 +3,55 @@ module github.com/nyaruka/courier go 1.18 require ( - github.com/antchfx/xmlquery v0.0.0-20181223105952-355641961c92 + github.com/antchfx/xmlquery v1.3.12 github.com/buger/jsonparser v1.1.1 - github.com/dghubble/oauth1 v0.4.0 - github.com/evalphobia/logrus_sentry v0.4.6 + github.com/dghubble/oauth1 v0.7.1 + github.com/evalphobia/logrus_sentry v0.8.2 github.com/go-chi/chi v4.1.2+incompatible - github.com/go-errors/errors v1.0.1 github.com/gofrs/uuid v4.2.0+incompatible - github.com/gomodule/redigo v1.8.8 - github.com/gorilla/schema v1.0.2 + github.com/gomodule/redigo v1.8.9 + github.com/gorilla/schema v1.2.0 github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.6 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.22.2 - github.com/nyaruka/null v1.1.1 + github.com/nyaruka/gocommon v1.24.0 + github.com/nyaruka/null v1.2.0 github.com/nyaruka/redisx v0.2.1 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 - github.com/sirupsen/logrus v1.8.1 - github.com/stretchr/testify v1.7.2 - golang.org/x/mod v0.4.2 + github.com/sirupsen/logrus v1.9.0 + github.com/stretchr/testify v1.8.0 + golang.org/x/mod v0.5.1 gopkg.in/go-playground/validator.v9 v9.31.0 gopkg.in/h2non/filetype.v1 v1.0.5 ) require ( - github.com/antchfx/xpath v0.0.0-20181208024549-4bbdf6db12aa // indirect - github.com/aws/aws-sdk-go v1.44.34 // indirect - github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 // indirect + github.com/antchfx/xpath v1.2.1 // indirect + github.com/aws/aws-sdk-go v1.44.67 // indirect + github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fatih/structs v1.0.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.0 // indirect - github.com/getsentry/raven-go v0.0.0-20180517221441-ed7bcb39ff10 // indirect + github.com/fatih/structs v1.1.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.1 // indirect + github.com/getsentry/raven-go v0.2.0 // indirect github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/kr/pretty v0.1.0 // indirect - github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 // indirect + github.com/kr/pretty v0.3.0 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/naoina/go-stringutil v0.1.0 // indirect github.com/naoina/toml v0.1.1 // indirect github.com/nyaruka/librato v1.0.0 // indirect - github.com/nyaruka/phonenumbers v1.0.75 // indirect + github.com/nyaruka/phonenumbers v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect - golang.org/x/net v0.0.0-20220614195744-fb05da6f9022 // indirect - golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098 // indirect + golang.org/x/net v0.0.0-20220728211354-c7608f3a8462 // indirect + golang.org/x/sys v0.0.0-20220731174439-a90be440212d // indirect golang.org/x/text v0.3.7 // indirect - google.golang.org/protobuf v1.28.0 // indirect - gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 27dc64210..9168bdef0 100644 --- a/go.sum +++ b/go.sum @@ -1,30 +1,30 @@ -github.com/antchfx/xmlquery v0.0.0-20181223105952-355641961c92 h1:4EgP6xLAdrD/TRlbSw4n2W6h68K2P3+R7lKqFoL5U9Q= -github.com/antchfx/xmlquery v0.0.0-20181223105952-355641961c92/go.mod h1:/+CnyD/DzHRnv2eRxrVbieRU/FIF6N0C+7oTtyUtCKk= -github.com/antchfx/xpath v0.0.0-20181208024549-4bbdf6db12aa h1:lL66YnJWy1tHlhjSx8fXnpgmv8kQVYnI4ilbYpNB6Zs= -github.com/antchfx/xpath v0.0.0-20181208024549-4bbdf6db12aa/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= -github.com/aws/aws-sdk-go v1.44.34 h1:+ZtWIbtSGLNB99P8eBrxXfJZgiIouzUbpkf/MNxq2yQ= -github.com/aws/aws-sdk-go v1.44.34/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/antchfx/xmlquery v1.3.12 h1:6TMGpdjpO/P8VhjnaYPXuqT3qyJ/VsqoyNTmJzNBTQ4= +github.com/antchfx/xmlquery v1.3.12/go.mod h1:3w2RvQvTz+DaT5fSgsELkSJcdNgkmg6vuXDEuhdwsPQ= +github.com/antchfx/xpath v1.2.1 h1:qhp4EW6aCOVr5XIkT+l6LJ9ck/JsUH/yyauNgTQkBF8= +github.com/antchfx/xpath v1.2.1/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= +github.com/aws/aws-sdk-go v1.44.67 h1:+nxfXbMe8QUB6svLsuLYsp+WhZBKM26w62Zidir739A= +github.com/aws/aws-sdk-go v1.44.67/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 h1:6/yVvBsKeAw05IUj4AzvrxaCnDjN4nUqKjW9+w5wixg= -github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= +github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s= +github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dghubble/oauth1 v0.4.0 h1:+MpOsgByu02lzT4pRGei5d2p6nAgj8yDwF3RASrgNPQ= -github.com/dghubble/oauth1 v0.4.0/go.mod h1:8V8BMV9DJRREZx/lUaHtrs7GUMXpzbMqJxINCasxYug= -github.com/evalphobia/logrus_sentry v0.4.6 h1:825MLGu+SW5H8hMXGeBI7TwX7vgJLd9hz0Eth1Mnp3o= -github.com/evalphobia/logrus_sentry v0.4.6/go.mod h1:pKcp+vriitUqu9KiWj/VRFbRfFNUwz95/UkgG8a6MNc= -github.com/fatih/structs v1.0.0 h1:BrX964Rv5uQ3wwS+KRUAJCBBw5PQmgJfJ6v4yly5QwU= +github.com/dghubble/oauth1 v0.7.1 h1:JjbOVSVVkms9A4h/sTQy5Jb2nFuAAVb2qVYgenJPyrE= +github.com/dghubble/oauth1 v0.7.1/go.mod h1:0eEzON0UY/OLACQrmnjgJjmvCGXzjBCsZqL1kWDXtF0= +github.com/evalphobia/logrus_sentry v0.8.2 h1:dotxHq+YLZsT1Bb45bB5UQbfCh3gM/nFFetyN46VoDQ= +github.com/evalphobia/logrus_sentry v0.8.2/go.mod h1:pKcp+vriitUqu9KiWj/VRFbRfFNUwz95/UkgG8a6MNc= github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/gabriel-vasile/mimetype v1.4.0 h1:Cn9dkdYsMIu56tGho+fqzh7XmvY2YyGU0FnbhiOsEro= -github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8= -github.com/getsentry/raven-go v0.0.0-20180517221441-ed7bcb39ff10 h1:YO10pIIBftO/kkTFdWhctH96grJ7qiy7bMdiZcIvPKs= -github.com/getsentry/raven-go v0.0.0-20180517221441-ed7bcb39ff10/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/gabriel-vasile/mimetype v1.4.1 h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkFtf/dnN7Q= +github.com/gabriel-vasile/mimetype v1.4.1/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M= +github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= -github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= @@ -33,16 +33,18 @@ github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfC github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/gomodule/redigo v1.8.8 h1:f6cXq6RRfiyrOJEV7p3JhLDlmawGBVBBP1MggY8Mo4E= -github.com/gomodule/redigo v1.8.8/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE= +github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws= +github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/gorilla/schema v1.0.2 h1:sAgNfOcNYvdDSrzGHVy9nzCQahG+qmsg+nE8dK85QRA= -github.com/gorilla/schema v1.0.2/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= +github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= +github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -50,13 +52,16 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfC github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4= -github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -71,14 +76,14 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.22.2 h1:iEusd0CijvYvhW+bEZ6LWYQuaXS4Oac5WH9W8iK6DEw= -github.com/nyaruka/gocommon v1.22.2/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= +github.com/nyaruka/gocommon v1.24.0 h1:zfluRa4h+Ms3hmed2vPov+PR/vWxtrTgBUEONRuuiIQ= +github.com/nyaruka/gocommon v1.24.0/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= -github.com/nyaruka/null v1.1.1 h1:kRy1Luj7jUHWEFqc2J6VXrKYi/beLEZdS1C7rA6vqTE= -github.com/nyaruka/null v1.1.1/go.mod h1:HSAFbLNOaEhHnoU0VCveCPz0GDtJ3GEtFWhvnBNkhPE= -github.com/nyaruka/phonenumbers v1.0.75 h1:OCwKXSjTi6IzuI4gVi8zfY+0s60DQUC6ks8Ll4j0eyU= -github.com/nyaruka/phonenumbers v1.0.75/go.mod h1:cGaEsOrLjIL0iKGqJR5Rfywy86dSkbApEpXuM9KySNA= +github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= +github.com/nyaruka/null v1.2.0/go.mod h1:HSAFbLNOaEhHnoU0VCveCPz0GDtJ3GEtFWhvnBNkhPE= +github.com/nyaruka/phonenumbers v1.1.0 h1:OvNAOAl4A9a2kNpzziITbUVH4bBBeKHkHl0llPmkxaA= +github.com/nyaruka/phonenumbers v1.1.0/go.mod h1:cGaEsOrLjIL0iKGqJR5Rfywy86dSkbApEpXuM9KySNA= github.com/nyaruka/redisx v0.2.1 h1:BavpQRCsK5xV2uxPdJJ26yVmjSo+q6bdjWqeNNf0s5w= github.com/nyaruka/redisx v0.2.1/go.mod h1:cdbAm4y/+oFWu7qFzH2ERPeqRXJC2CtgRhwcBacM4Oc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= @@ -87,61 +92,53 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220614195744-fb05da6f9022 h1:0qjDla5xICC2suMtyRH/QqX3B1btXTfNsIt/i4LFgO0= -golang.org/x/net v0.0.0-20220614195744-fb05da6f9022/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220728211354-c7608f3a8462 h1:UreQrH7DbFXSi9ZFox6FNT3WBooWmdANpU+IfkT1T4I= +golang.org/x/net v0.0.0-20220728211354-c7608f3a8462/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098 h1:PgOr27OhUx2IRqGJ2RxAWI4dJQ7bi9cSrB82uzFzfUA= -golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220731174439-a90be440212d h1:Sv5ogFZatcgIMMtBSTTAgMYsicp25MXBubjXNDKwm80= +golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M= gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index 499fe75f9..b6b8cd013 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -11,12 +11,12 @@ import ( "time" "github.com/buger/jsonparser" - "github.com/go-errors/errors" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/jsonx" "github.com/nyaruka/gocommon/urns" + "github.com/pkg/errors" ) var apiURL = "https://api.telegram.org" diff --git a/handlers/vk/vk.go b/handlers/vk/vk.go index 1f39c9a85..9011088d9 100644 --- a/handlers/vk/vk.go +++ b/handlers/vk/vk.go @@ -15,12 +15,12 @@ import ( "time" "github.com/buger/jsonparser" - "github.com/go-errors/errors" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/jsonx" "github.com/nyaruka/gocommon/urns" + "github.com/pkg/errors" ) var ( From 18a1c1fe72360db4dff300961dd42b13243aeedb Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 2 Aug 2022 11:00:26 -0500 Subject: [PATCH 031/294] Switch channel loading to use null.Map and cleanup SQL --- backends/rapidpro/backend_test.go | 6 +- backends/rapidpro/channel.go | 113 +++++++++++++----------------- 2 files changed, 50 insertions(+), 69 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index c84f5c8b1..41addee9f 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -90,11 +90,11 @@ func (ts *BackendTestSuite) TearDownSuite() { func (ts *BackendTestSuite) getChannel(cType string, cUUID string) *DBChannel { channelUUID, err := courier.NewChannelUUID(cUUID) - ts.NoError(err, "error building channel uuid") + ts.Require().NoError(err, "error building channel uuid") channel, err := ts.b.GetChannel(context.Background(), courier.ChannelType(cType), channelUUID) - ts.NoError(err, "error getting channel") - ts.NotNil(channel) + ts.Require().NoError(err, "error getting channel") + ts.Require().NotNil(channel) return channel.(*DBChannel) } diff --git a/backends/rapidpro/channel.go b/backends/rapidpro/channel.go index 268182c89..1f7f6e086 100644 --- a/backends/rapidpro/channel.go +++ b/backends/rapidpro/channel.go @@ -12,7 +12,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/lib/pq" "github.com/nyaruka/courier" - "github.com/nyaruka/courier/utils" + "github.com/nyaruka/null" ) // getChannel will look up the channel with the passed in UUID and channel type. @@ -50,32 +50,30 @@ func getChannel(ctx context.Context, db *sqlx.DB, channelType courier.ChannelTyp return channel, nil } -const lookupChannelFromUUIDSQL = ` -SELECT - org_id, - ch.id as id, - ch.uuid as uuid, - ch.name as name, - channel_type, schemes, - address, role, - ch.country as country, - ch.config as config, - org.config as org_config, - org.is_anon as org_is_anon -FROM - channels_channel ch - JOIN orgs_org org on ch.org_id = org.id -WHERE - ch.uuid = $1 AND - ch.is_active = true AND - ch.org_id IS NOT NULL` +const sqlLookupChannelFromUUID = ` +SELECT + c.uuid, + c.org_id, + c.id, + c.channel_type, + c.name, + c.schemes, + c.address, + c.country, + c.config, + c.role, + o.config AS org_config, + o.is_anon AS org_is_anon + FROM channels_channel c + JOIN orgs_org o ON c.org_id = o.id + WHERE c.uuid = $1 AND c.is_active = TRUE AND c.org_id IS NOT NULL` // ChannelForUUID attempts to look up the channel with the passed in UUID, returning it func loadChannelFromDB(ctx context.Context, db *sqlx.DB, channelType courier.ChannelType, uuid courier.ChannelUUID) (*DBChannel, error) { channel := &DBChannel{UUID_: uuid} // select just the fields we need - err := db.GetContext(ctx, channel, lookupChannelFromUUIDSQL, uuid) + err := db.GetContext(ctx, channel, sqlLookupChannelFromUUID, uuid) // we didn't find a match if err == sql.ErrNoRows { @@ -175,32 +173,30 @@ func getChannelByAddress(ctx context.Context, db *sqlx.DB, channelType courier.C return channel, nil } -const lookupChannelFromAddressSQL = ` +const sqlLookupChannelFromAddress = ` SELECT - org_id, - ch.id as id, - ch.uuid as uuid, - ch.name as name, - channel_type, schemes, - address, - ch.country as country, - ch.config as config, - org.config as org_config, - org.is_anon as org_is_anon -FROM - channels_channel ch - JOIN orgs_org org on ch.org_id = org.id -WHERE - ch.address = $1 AND - ch.is_active = true AND - ch.org_id IS NOT NULL` + c.uuid, + c.org_id, + c.id, + c.channel_type, + c.name, + c.schemes, + c.address, + c.country, + c.config, + c.role, + o.config AS org_config, + o.is_anon AS org_is_anon + FROM channels_channel c + JOIN orgs_org o ON c.org_id = o.id + WHERE c.address = $1 AND c.is_active = TRUE AND c.org_id IS NOT NULL` // loadChannelByAddressFromDB get the channel with the passed in channel type and address from the DB, returning it func loadChannelByAddressFromDB(ctx context.Context, db *sqlx.DB, channelType courier.ChannelType, address courier.ChannelAddress) (*DBChannel, error) { channel := &DBChannel{Address_: sql.NullString{String: address.String(), Valid: address == courier.NilChannelAddress}} // select just the fields we need - err := db.GetContext(ctx, channel, lookupChannelFromAddressSQL, address) + err := db.GetContext(ctx, channel, sqlLookupChannelFromAddress, address) // we didn't find a match if err == sql.ErrNoRows { @@ -275,18 +271,18 @@ var channelByAddressCache = make(map[courier.ChannelAddress]*DBChannel) // DBChannel is the RapidPro specific concrete type satisfying the courier.Channel interface type DBChannel struct { OrgID_ OrgID `db:"org_id"` + UUID_ courier.ChannelUUID `db:"uuid"` ID_ courier.ChannelID `db:"id"` ChannelType_ courier.ChannelType `db:"channel_type"` Schemes_ pq.StringArray `db:"schemes"` - UUID_ courier.ChannelUUID `db:"uuid"` Name_ sql.NullString `db:"name"` Address_ sql.NullString `db:"address"` Country_ sql.NullString `db:"country"` - Config_ utils.NullMap `db:"config"` + Config_ null.Map `db:"config"` Role_ string `db:"role"` - OrgConfig_ utils.NullMap `db:"org_config"` - OrgIsAnon_ bool `db:"org_is_anon"` + OrgConfig_ null.Map `db:"org_config"` + OrgIsAnon_ bool `db:"org_is_anon"` expiration time.Time } @@ -353,12 +349,7 @@ func (c *DBChannel) HasRole(role courier.ChannelRole) bool { // ConfigForKey returns the config value for the passed in key, or defaultValue if it isn't found func (c *DBChannel) ConfigForKey(key string, defaultValue interface{}) interface{} { - // no value, return our default value - if !c.Config_.Valid { - return defaultValue - } - - value, found := c.Config_.Map[key] + value, found := c.Config_.Map()[key] if !found { return defaultValue } @@ -367,28 +358,13 @@ func (c *DBChannel) ConfigForKey(key string, defaultValue interface{}) interface // OrgConfigForKey returns the org config value for the passed in key, or defaultValue if it isn't found func (c *DBChannel) OrgConfigForKey(key string, defaultValue interface{}) interface{} { - // no value, return our default value - if !c.OrgConfig_.Valid { - return defaultValue - } - - value, found := c.OrgConfig_.Map[key] + value, found := c.OrgConfig_.Map()[key] if !found { return defaultValue } return value } -// CallbackDomain returns the callback domain to use for this channel -func (c *DBChannel) CallbackDomain(fallbackDomain string) string { - value, found := c.Config_.Map[courier.ConfigCallbackDomain] - strValue, isStr := value.(string) - if !found || !isStr { - return fallbackDomain - } - return strValue -} - // StringConfigForKey returns the config value for the passed in key, or defaultValue if it isn't found func (c *DBChannel) StringConfigForKey(key string, defaultValue string) string { val := c.ConfigForKey(key, defaultValue) @@ -429,6 +405,11 @@ func (c *DBChannel) IntConfigForKey(key string, defaultValue int) int { return defaultValue } +// CallbackDomain is convenience utility to get the callback domain configured for this channel +func (c *DBChannel) CallbackDomain(fallbackDomain string) string { + return c.StringConfigForKey(courier.ConfigCallbackDomain, fallbackDomain) +} + // supportsScheme returns whether the passed in channel supports the passed in scheme func (c *DBChannel) supportsScheme(scheme string) bool { for _, s := range c.Schemes_ { From 6ec44e1944dac757154edcad18fb4c97be3e2af2 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 2 Aug 2022 11:11:01 -0500 Subject: [PATCH 032/294] Rework DBChannelEvent to use null.Map --- backends/rapidpro/backend_test.go | 4 +- backends/rapidpro/channel_event.go | 23 +++------ utils/db.go | 79 ------------------------------ 3 files changed, 10 insertions(+), 96 deletions(-) delete mode 100644 utils/db.go diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 41addee9f..f70c3a386 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -1199,7 +1199,7 @@ func (ts *BackendTestSuite) TestChannelEvent() { dbE, err = readChannelEventFromDB(ts.b, dbE.ID_) ts.NoError(err) ts.Equal(dbE.EventType_, courier.Referral) - ts.Equal(map[string]interface{}{"ref_id": "12345"}, dbE.Extra_.Map) + ts.Equal(map[string]interface{}{"ref_id": "12345"}, dbE.Extra_.Map()) ts.Equal(contact.ID_, dbE.ContactID_) ts.Equal(contact.URNID_, dbE.ContactURNID_) } @@ -1241,7 +1241,7 @@ func (ts *BackendTestSuite) TestMailroomEvents() { dbE, err = readChannelEventFromDB(ts.b, dbE.ID_) ts.NoError(err) ts.Equal(dbE.EventType_, courier.Referral) - ts.Equal(map[string]interface{}{"ref_id": "12345"}, dbE.Extra_.Map) + ts.Equal(map[string]interface{}{"ref_id": "12345"}, dbE.Extra_.Map()) ts.Equal(contact.ID_, dbE.ContactID_) ts.Equal(contact.URNID_, dbE.ContactURNID_) diff --git a/backends/rapidpro/channel_event.go b/backends/rapidpro/channel_event.go index 2f47001f2..d81879d8f 100644 --- a/backends/rapidpro/channel_event.go +++ b/backends/rapidpro/channel_event.go @@ -13,7 +13,6 @@ import ( "github.com/nyaruka/null" "github.com/nyaruka/courier" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" "github.com/sirupsen/logrus" ) @@ -189,7 +188,7 @@ type DBChannelEvent struct { ChannelID_ courier.ChannelID `json:"channel_id" db:"channel_id"` URN_ urns.URN `json:"urn" db:"urn"` EventType_ courier.ChannelEventType `json:"event_type" db:"event_type"` - Extra_ *utils.NullMap `json:"extra" db:"extra"` + Extra_ null.Map `json:"extra" db:"extra"` OccurredOn_ time.Time `json:"occurred_on" db:"occurred_on"` CreatedOn_ time.Time `json:"created_on" db:"created_on"` @@ -201,17 +200,12 @@ type DBChannelEvent struct { logs []*courier.ChannelLog } -func (e *DBChannelEvent) EventID() int64 { return int64(e.ID_) } -func (e *DBChannelEvent) ChannelID() courier.ChannelID { return e.ChannelID_ } -func (e *DBChannelEvent) ChannelUUID() courier.ChannelUUID { return e.ChannelUUID_ } -func (e *DBChannelEvent) ContactName() string { return e.ContactName_ } -func (e *DBChannelEvent) URN() urns.URN { return e.URN_ } -func (e *DBChannelEvent) Extra() map[string]interface{} { - if e.Extra_ != nil { - return e.Extra_.Map - } - return nil -} +func (e *DBChannelEvent) EventID() int64 { return int64(e.ID_) } +func (e *DBChannelEvent) ChannelID() courier.ChannelID { return e.ChannelID_ } +func (e *DBChannelEvent) ChannelUUID() courier.ChannelUUID { return e.ChannelUUID_ } +func (e *DBChannelEvent) ContactName() string { return e.ContactName_ } +func (e *DBChannelEvent) URN() urns.URN { return e.URN_ } +func (e *DBChannelEvent) Extra() map[string]interface{} { return e.Extra_.Map() } func (e *DBChannelEvent) EventType() courier.ChannelEventType { return e.EventType_ } func (e *DBChannelEvent) OccurredOn() time.Time { return e.OccurredOn_ } func (e *DBChannelEvent) CreatedOn() time.Time { return e.CreatedOn_ } @@ -222,8 +216,7 @@ func (e *DBChannelEvent) WithContactName(name string) courier.ChannelEvent { return e } func (e *DBChannelEvent) WithExtra(extra map[string]interface{}) courier.ChannelEvent { - newExtra := utils.NewNullMap(extra) - e.Extra_ = &newExtra + e.Extra_ = null.NewMap(extra) return e } diff --git a/utils/db.go b/utils/db.go deleted file mode 100644 index da5d84515..000000000 --- a/utils/db.go +++ /dev/null @@ -1,79 +0,0 @@ -package utils - -import ( - "database/sql/driver" - "encoding/json" - "errors" -) - -// NewNullMap creates a new null map with the passed in map -func NewNullMap(validMap map[string]interface{}) NullMap { - return NullMap{Map: validMap, Valid: true} -} - -// NullMap is a one level deep dictionary that is represented as JSON in the database -type NullMap struct { - Map map[string]interface{} - Valid bool -} - -// Scan implements the Scanner interface for decoding from a database -func (n *NullMap) Scan(src interface{}) error { - if src == nil { - return nil - } - - var source []byte - switch src.(type) { - case string: - source = []byte(src.(string)) - case []byte: - source = src.([]byte) - default: - return errors.New("Incompatible type for NullDict") - } - - // 0 length is same as nil - if len(source) == 0 { - return nil - } - - n.Map = make(map[string]interface{}) - n.Valid = true - return json.Unmarshal(source, &n.Map) -} - -// Value implements the driver Valuer interface -func (n *NullMap) Value() (driver.Value, error) { - if n == nil { - return nil, nil - } - - if !n.Valid { - return nil, nil - } - - if len(n.Map) == 0 { - return nil, nil - } - return json.Marshal(n.Map) -} - -// MarshalJSON decodes our dictionary from the passed in bytes -func (n *NullMap) MarshalJSON() ([]byte, error) { - if !n.Valid { - return json.Marshal(nil) - } - return json.Marshal(n.Map) -} - -// UnmarshalJSON sets our dict from the passed in data -func (n *NullMap) UnmarshalJSON(data []byte) error { - if len(data) == 0 { - return nil - } - - n.Map = make(map[string]interface{}) - n.Valid = true - return json.Unmarshal(data, &n.Map) -} From e7ba958abdca1c3e9913fe5db1caafbf2a3ed5e9 Mon Sep 17 00:00:00 2001 From: Tyler Britten <1933680+tybritten@users.noreply.github.com> Date: Tue, 2 Aug 2022 12:16:13 -0400 Subject: [PATCH 033/294] Add AWS Cred Chain support for s3 --- backends/rapidpro/backend.go | 11 ++++++++--- config.go | 3 +++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 62c83809f..8c6b983d5 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -657,8 +657,8 @@ func (b *backend) Start() error { } // create our storage (S3 or file system) - if b.config.AWSAccessKeyID != "" { - s3Client, err := storage.NewS3Client(&storage.S3Options{ + if b.config.AWSAccessKeyID != "" || b.config.AWSUseCredChain { + s3config := &storage.S3Options{ AWSAccessKeyID: b.config.AWSAccessKeyID, AWSSecretAccessKey: b.config.AWSSecretAccessKey, Endpoint: b.config.S3Endpoint, @@ -666,7 +666,12 @@ func (b *backend) Start() error { DisableSSL: b.config.S3DisableSSL, ForcePathStyle: b.config.S3ForcePathStyle, MaxRetries: 3, - }) + } + if b.config.AWSAccessKeyID != "" && !b.config.AWSUseCredChain { + s3config.AWSAccessKeyID = b.config.AWSAccessKeyID + s3config.AWSSecretAccessKey = b.config.AWSSecretAccessKey + } + s3Client, err := storage.NewS3Client(s3config) if err != nil { return err } diff --git a/config.go b/config.go index fb9d59a5b..13ef37783 100644 --- a/config.go +++ b/config.go @@ -20,6 +20,8 @@ type Config struct { S3ForcePathStyle bool `help:"whether we force S3 path style. Should generally need to default to False unless you're hosting an S3 compatible service"` AWSAccessKeyID string `help:"the access key id to use when authenticating S3"` AWSSecretAccessKey string `help:"the secret access key id to use when authenticating S3"` + AWSUseCredChain bool `help:"whether to use the AWS credentials chain. Defaults to false."` + FacebookApplicationSecret string `help:"the Facebook app secret"` FacebookWebhookSecret string `help:"the secret for Facebook webhook URL verification"` MaxWorkers int `help:"the maximum number of go routines that will be used for sending (set to 0 to disable sending)"` @@ -57,6 +59,7 @@ func NewConfig() *Config { S3ForcePathStyle: false, AWSAccessKeyID: "", AWSSecretAccessKey: "", + AWSUseCredChain: false, FacebookApplicationSecret: "missing_facebook_app_secret", FacebookWebhookSecret: "missing_facebook_webhook_secret", WhatsappAdminSystemUserToken: "missing_whatsapp_admin_system_user_token", From 7f8a7aa435a661933907adb3d1ff91deed3c1d73 Mon Sep 17 00:00:00 2001 From: Tyler Britten <1933680+tybritten@users.noreply.github.com> Date: Tue, 2 Aug 2022 12:24:11 -0400 Subject: [PATCH 034/294] gofmt --- backends/rapidpro/backend.go | 2 +- config.go | 36 ++++++++++++++++++------------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 8c6b983d5..83204ce7a 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -668,7 +668,7 @@ func (b *backend) Start() error { MaxRetries: 3, } if b.config.AWSAccessKeyID != "" && !b.config.AWSUseCredChain { - s3config.AWSAccessKeyID = b.config.AWSAccessKeyID + s3config.AWSAccessKeyID = b.config.AWSAccessKeyID s3config.AWSSecretAccessKey = b.config.AWSSecretAccessKey } s3Client, err := storage.NewS3Client(s3config) diff --git a/config.go b/config.go index 13ef37783..fee90d318 100644 --- a/config.go +++ b/config.go @@ -4,23 +4,23 @@ import "github.com/nyaruka/ezconf" // Config is our top level configuration object type Config struct { - Backend string `help:"the backend that will be used by courier (currently only rapidpro is supported)"` - SentryDSN string `help:"the DSN used for logging errors to Sentry"` - Domain string `help:"the domain courier is exposed on"` - Address string `help:"the network interface address courier will bind to"` - Port int `help:"the port courier will listen on"` - DB string `help:"URL describing how to connect to the RapidPro database"` - Redis string `help:"URL describing how to connect to Redis"` - SpoolDir string `help:"the local directory where courier will write statuses or msgs that need to be retried (needs to be writable)"` - S3Endpoint string `help:"the S3 endpoint we will write attachments to"` - S3Region string `help:"the S3 region we will write attachments to"` - S3MediaBucket string `help:"the S3 bucket we will write attachments to"` - S3MediaPrefix string `help:"the prefix that will be added to attachment filenames"` - S3DisableSSL bool `help:"whether we disable SSL when accessing S3. Should always be set to False unless you're hosting an S3 compatible service within a secure internal network"` - S3ForcePathStyle bool `help:"whether we force S3 path style. Should generally need to default to False unless you're hosting an S3 compatible service"` - AWSAccessKeyID string `help:"the access key id to use when authenticating S3"` - AWSSecretAccessKey string `help:"the secret access key id to use when authenticating S3"` - AWSUseCredChain bool `help:"whether to use the AWS credentials chain. Defaults to false."` + Backend string `help:"the backend that will be used by courier (currently only rapidpro is supported)"` + SentryDSN string `help:"the DSN used for logging errors to Sentry"` + Domain string `help:"the domain courier is exposed on"` + Address string `help:"the network interface address courier will bind to"` + Port int `help:"the port courier will listen on"` + DB string `help:"URL describing how to connect to the RapidPro database"` + Redis string `help:"URL describing how to connect to Redis"` + SpoolDir string `help:"the local directory where courier will write statuses or msgs that need to be retried (needs to be writable)"` + S3Endpoint string `help:"the S3 endpoint we will write attachments to"` + S3Region string `help:"the S3 region we will write attachments to"` + S3MediaBucket string `help:"the S3 bucket we will write attachments to"` + S3MediaPrefix string `help:"the prefix that will be added to attachment filenames"` + S3DisableSSL bool `help:"whether we disable SSL when accessing S3. Should always be set to False unless you're hosting an S3 compatible service within a secure internal network"` + S3ForcePathStyle bool `help:"whether we force S3 path style. Should generally need to default to False unless you're hosting an S3 compatible service"` + AWSAccessKeyID string `help:"the access key id to use when authenticating S3"` + AWSSecretAccessKey string `help:"the secret access key id to use when authenticating S3"` + AWSUseCredChain bool `help:"whether to use the AWS credentials chain. Defaults to false."` FacebookApplicationSecret string `help:"the Facebook app secret"` FacebookWebhookSecret string `help:"the secret for Facebook webhook URL verification"` @@ -59,7 +59,7 @@ func NewConfig() *Config { S3ForcePathStyle: false, AWSAccessKeyID: "", AWSSecretAccessKey: "", - AWSUseCredChain: false, + AWSUseCredChain: false, FacebookApplicationSecret: "missing_facebook_app_secret", FacebookWebhookSecret: "missing_facebook_webhook_secret", WhatsappAdminSystemUserToken: "missing_whatsapp_admin_system_user_token", From 7f95ab9351a5663937bc7092bda8ba6ce589c2cc Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 2 Aug 2022 12:30:29 -0500 Subject: [PATCH 035/294] Update to latest gocommon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a5d72b611..e60c4a6d7 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.6 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.24.0 + github.com/nyaruka/gocommon v1.24.1 github.com/nyaruka/null v1.2.0 github.com/nyaruka/redisx v0.2.1 github.com/patrickmn/go-cache v2.1.0+incompatible diff --git a/go.sum b/go.sum index 9168bdef0..929219873 100644 --- a/go.sum +++ b/go.sum @@ -76,8 +76,8 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.24.0 h1:zfluRa4h+Ms3hmed2vPov+PR/vWxtrTgBUEONRuuiIQ= -github.com/nyaruka/gocommon v1.24.0/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= +github.com/nyaruka/gocommon v1.24.1 h1:JiAxkDPnsGinnM35nEpyKanXUFzM8GsW+SUxlzUzGc4= +github.com/nyaruka/gocommon v1.24.1/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= From 48be950e1facb5da2ee71acf2f050fd7106c126b Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 2 Aug 2022 12:33:23 -0500 Subject: [PATCH 036/294] Better organize config entries --- config.go | 84 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/config.go b/config.go index fee90d318..401371209 100644 --- a/config.go +++ b/config.go @@ -4,36 +4,37 @@ import "github.com/nyaruka/ezconf" // Config is our top level configuration object type Config struct { - Backend string `help:"the backend that will be used by courier (currently only rapidpro is supported)"` - SentryDSN string `help:"the DSN used for logging errors to Sentry"` - Domain string `help:"the domain courier is exposed on"` - Address string `help:"the network interface address courier will bind to"` - Port int `help:"the port courier will listen on"` - DB string `help:"URL describing how to connect to the RapidPro database"` - Redis string `help:"URL describing how to connect to Redis"` - SpoolDir string `help:"the local directory where courier will write statuses or msgs that need to be retried (needs to be writable)"` + Backend string `help:"the backend that will be used by courier (currently only rapidpro is supported)"` + SentryDSN string `help:"the DSN used for logging errors to Sentry"` + Domain string `help:"the domain courier is exposed on"` + Address string `help:"the network interface address courier will bind to"` + Port int `help:"the port courier will listen on"` + DB string `help:"URL describing how to connect to the RapidPro database"` + Redis string `help:"URL describing how to connect to Redis"` + SpoolDir string `help:"the local directory where courier will write statuses or msgs that need to be retried (needs to be writable)"` + + AWSAccessKeyID string `help:"the access key id to use when authenticating S3"` + AWSSecretAccessKey string `help:"the secret access key id to use when authenticating S3"` + AWSUseCredChain bool `help:"whether to use the AWS credentials chain. Defaults to false."` S3Endpoint string `help:"the S3 endpoint we will write attachments to"` S3Region string `help:"the S3 region we will write attachments to"` S3MediaBucket string `help:"the S3 bucket we will write attachments to"` S3MediaPrefix string `help:"the prefix that will be added to attachment filenames"` S3DisableSSL bool `help:"whether we disable SSL when accessing S3. Should always be set to False unless you're hosting an S3 compatible service within a secure internal network"` S3ForcePathStyle bool `help:"whether we force S3 path style. Should generally need to default to False unless you're hosting an S3 compatible service"` - AWSAccessKeyID string `help:"the access key id to use when authenticating S3"` - AWSSecretAccessKey string `help:"the secret access key id to use when authenticating S3"` - AWSUseCredChain bool `help:"whether to use the AWS credentials chain. Defaults to false."` - - FacebookApplicationSecret string `help:"the Facebook app secret"` - FacebookWebhookSecret string `help:"the secret for Facebook webhook URL verification"` - MaxWorkers int `help:"the maximum number of go routines that will be used for sending (set to 0 to disable sending)"` - LibratoUsername string `help:"the username that will be used to authenticate to Librato"` - LibratoToken string `help:"the token that will be used to authenticate to Librato"` - StatusUsername string `help:"the username that is needed to authenticate against the /status endpoint"` - StatusPassword string `help:"the password that is needed to authenticate against the /status endpoint"` - LogLevel string `help:"the logging level courier should use"` - Version string `help:"the version that will be used in request and response headers"` + FacebookApplicationSecret string `help:"the Facebook app secret"` + FacebookWebhookSecret string `help:"the secret for Facebook webhook URL verification"` WhatsappAdminSystemUserToken string `help:"the token of the admin system user for WhatsApp"` + MaxWorkers int `help:"the maximum number of go routines that will be used for sending (set to 0 to disable sending)"` + LibratoUsername string `help:"the username that will be used to authenticate to Librato"` + LibratoToken string `help:"the token that will be used to authenticate to Librato"` + StatusUsername string `help:"the username that is needed to authenticate against the /status endpoint"` + StatusPassword string `help:"the password that is needed to authenticate against the /status endpoint"` + LogLevel string `help:"the logging level courier should use"` + Version string `help:"the version that will be used in request and response headers"` + // IncludeChannels is the list of channels to enable, empty means include all IncludeChannels []string @@ -44,28 +45,31 @@ type Config struct { // NewConfig returns a new default configuration object func NewConfig() *Config { return &Config{ - Backend: "rapidpro", - Domain: "localhost", - Address: "", - Port: 8080, - DB: "postgres://temba:temba@localhost/temba?sslmode=disable", - Redis: "redis://localhost:6379/15", - SpoolDir: "/var/spool/courier", - S3Endpoint: "https://s3.amazonaws.com", - S3Region: "us-east-1", - S3MediaBucket: "courier-media", - S3MediaPrefix: "/media/", - S3DisableSSL: false, - S3ForcePathStyle: false, - AWSAccessKeyID: "", - AWSSecretAccessKey: "", - AWSUseCredChain: false, + Backend: "rapidpro", + Domain: "localhost", + Address: "", + Port: 8080, + DB: "postgres://temba:temba@localhost/temba?sslmode=disable", + Redis: "redis://localhost:6379/15", + SpoolDir: "/var/spool/courier", + + AWSAccessKeyID: "", + AWSSecretAccessKey: "", + AWSUseCredChain: false, + S3Endpoint: "https://s3.amazonaws.com", + S3Region: "us-east-1", + S3MediaBucket: "courier-media", + S3MediaPrefix: "/media/", + S3DisableSSL: false, + S3ForcePathStyle: false, + FacebookApplicationSecret: "missing_facebook_app_secret", FacebookWebhookSecret: "missing_facebook_webhook_secret", WhatsappAdminSystemUserToken: "missing_whatsapp_admin_system_user_token", - MaxWorkers: 32, - LogLevel: "error", - Version: "Dev", + + MaxWorkers: 32, + LogLevel: "error", + Version: "Dev", } } From f41ef351561728b9faeab0f6c5e2d628654d8368 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 2 Aug 2022 13:15:30 -0500 Subject: [PATCH 037/294] Update CHANGELOG.md for v7.5.4 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3c81085f..dc27d6269 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.4 +---------- + * Add AWS Cred Chain support for S3 + * Update deps and fix incorrect errors import in some handler packages + v7.5.3 ---------- * Fix receiving attachments in WAC From 8bee3f0184f027fe8d0d6df95901dd6068aa0af0 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 2 Aug 2022 12:39:47 -0500 Subject: [PATCH 038/294] Implement looking up media from database --- backend.go | 3 +- backends/rapidpro/backend.go | 57 +++++++++++++----- backends/rapidpro/backend_test.go | 97 +++++++++++++++++++++++++++++++ backends/rapidpro/media.go | 55 ++++++++++-------- backends/rapidpro/schema.sql | 15 +++++ backends/rapidpro/testdata.sql | 7 +++ go.mod | 2 +- go.sum | 4 +- test.go | 62 ++++++++++++++++++-- 9 files changed, 254 insertions(+), 48 deletions(-) diff --git a/backend.go b/backend.go index 8766b104f..0ec093c6e 100644 --- a/backend.go +++ b/backend.go @@ -109,10 +109,11 @@ type Media interface { UUID() uuids.UUID ContentType() string URL() string - Alternates() []Media + Size() int Width() int Height() int Duration() int + Alternates() []Media } // NewBackend creates the type of backend passed in diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 5531b022c..d1a6b890f 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -21,9 +21,12 @@ import ( "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/analytics" "github.com/nyaruka/gocommon/dbutil" + "github.com/nyaruka/gocommon/jsonx" "github.com/nyaruka/gocommon/storage" + "github.com/nyaruka/gocommon/syncx" "github.com/nyaruka/gocommon/urns" "github.com/nyaruka/gocommon/uuids" + "github.com/nyaruka/redisx" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -37,6 +40,8 @@ const sentSetName = "msgs_sent_%s" // our timeout for backend operations const backendTimeout = time.Second * 20 +var uuidRegex = regexp.MustCompile(`[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`) + func init() { courier.RegisterBackend("rapidpro", newBackend) } @@ -405,41 +410,57 @@ func (b *backend) WriteExternalIDSeen(msg courier.Msg) { writeExternalIDSeen(b, msg) } -var uuidRegex = regexp.MustCompile(`[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`) - // ResolveMedia resolves the passed in attachment (content_type:url) to a media object func (b *backend) ResolveMedia(ctx context.Context, a string) (courier.Media, error) { // split into content-type and URL parts := strings.SplitN(a, ":", 2) var contentType, mediaUrl string - if len(parts) < 2 { - contentType, mediaUrl = "", parts[0] - } else { - contentType, mediaUrl = parts[0], parts[1] + if len(parts) <= 1 || strings.HasPrefix(parts[1], "//") { + return nil, errors.Errorf("invalid attachment format: %s", a) } - // if we can't parse the URL or the hostname isn't our media domain, return as is + contentType, mediaUrl = parts[0], parts[1] + stub := &DBMedia{URL_: mediaUrl, ContentType_: contentType} + + // if we can't parse the URL or the hostname isn't our media domain, return stub u, err := url.Parse(mediaUrl) if err != nil || u.Hostname() != b.config.MediaDomain { - return &Media{URL_: mediaUrl, ContentType_: contentType}, nil + return stub, nil } - // likewise if path doesn't contain a UUID, return as is + // likewise if path doesn't contain a UUID, return stub mediaUUID := uuidRegex.FindString(u.Path) if mediaUUID == "" { - return &Media{URL_: mediaUrl, ContentType_: contentType}, nil + return stub, nil } - // TODO: lock and cache + unlock := b.mediaMutexes.Lock(mediaUUID) + defer unlock() + + rc := b.redisPool.Get() + defer rc.Close() - media, err := lookupMediaFromUUID(ctx, b.db, uuids.UUID(mediaUUID)) + var media *DBMedia + mediaJSON, err := b.mediaCache.Get(rc, mediaUUID) if err != nil { - return nil, errors.Wrap(err, "error looking up media") + return nil, errors.Wrap(err, "error looking up cached media") + } + if mediaJSON != "" { + jsonx.MustUnmarshal([]byte(mediaJSON), &media) + } else { + // lookup media in our database + media, err = lookupMediaFromUUID(ctx, b.db, uuids.UUID(mediaUUID)) + if err != nil { + return nil, errors.Wrap(err, "error looking up media") + } + + // cache it for future requests + b.mediaCache.Set(rc, mediaUUID, string(jsonx.MustMarshal(media))) } - // if we didn't find a media record or the one we found doesn't match the URL, return as is + // if we didn't find a media record or the one we found doesn't match the URL, return stub if media == nil || media.URL() != mediaUrl { - return &Media{URL_: mediaUrl, ContentType_: contentType}, nil + return stub, nil } return media, nil @@ -837,6 +858,9 @@ func newBackend(cfg *courier.Config) courier.Backend { waitGroup: &sync.WaitGroup{}, committerWG: &sync.WaitGroup{}, + + mediaCache: redisx.NewIntervalHash("media-lookups", time.Hour*24, 2), + mediaMutexes: *syncx.NewHashMutex(8), } } @@ -854,6 +878,9 @@ type backend struct { stopChan chan bool waitGroup *sync.WaitGroup + mediaCache *redisx.IntervalHash + mediaMutexes syncx.HashMutex + // both sqlx and redis provide wait stats which are cummulative that we need to convert into increments dbWaitDuration time.Duration dbWaitCount int64 diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index c84f5c8b1..07b20aa70 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -21,6 +21,7 @@ import ( "github.com/nyaruka/gocommon/storage" "github.com/nyaruka/gocommon/urns" "github.com/nyaruka/null" + "github.com/nyaruka/redisx/assertredis" "github.com/gomodule/redigo/redis" "github.com/sirupsen/logrus" @@ -38,6 +39,7 @@ func testConfig() *courier.Config { config := courier.NewConfig() config.DB = "postgres://courier:courier@localhost:5432/courier_test?sslmode=disable" config.Redis = "redis://localhost:6379/0" + config.MediaDomain = "nyaruka.s3.com" return config } @@ -1275,6 +1277,101 @@ func (ts *BackendTestSuite) TestMailroomEvents() { }, body["task"]) } +func (ts *BackendTestSuite) TestResolveMedia() { + ctx := context.Background() + + tcs := []struct { + attachment string + media *DBMedia + err string + }{ + { // user entered image URL + attachment: "image:https://example.com/test.png", + media: &DBMedia{ContentType_: "image", URL_: "https://example.com/test.png"}, + }, + { // user entered audio URL + attachment: "audio:https://example.com/test.mp3", + media: &DBMedia{ContentType_: "audio", URL_: "https://example.com/test.mp3"}, + }, + { // user entered unparseable URL + attachment: "video:https::/example.com/test.mp4", + media: &DBMedia{ContentType_: "video", URL_: "https::/example.com/test.mp4"}, + }, + { // image upload + attachment: "image/jpeg:http://nyaruka.s3.com/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg", + media: &DBMedia{ + UUID_: "ec6972be-809c-4c8d-be59-ba9dbd74c977", + ContentType_: "image/jpeg", + URL_: "http://nyaruka.s3.com/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg", + Size_: 123, + Width_: 1024, + Height_: 768, + Alternates_: []*DBMedia{}, + }, + }, + { // same image upload, this time from cache + attachment: "image/jpeg:http://nyaruka.s3.com/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg", + media: &DBMedia{ + UUID_: "ec6972be-809c-4c8d-be59-ba9dbd74c977", + ContentType_: "image/jpeg", + URL_: "http://nyaruka.s3.com/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg", + Size_: 123, + Width_: 1024, + Height_: 768, + Alternates_: []*DBMedia{}, + }, + }, + { // image upload but with wrong domain + attachment: "image/jpeg:http://temba.s2.com/orgs/1/media/f328/f32801ec-433a-4862-978d-56c1823b92b2/test.jpg", + media: &DBMedia{ + ContentType_: "image/jpeg", + URL_: "http://temba.s2.com/orgs/1/media/f328/f32801ec-433a-4862-978d-56c1823b92b2/test.jpg", + }, + }, + { // audio upload + attachment: "audio/mp3:http://nyaruka.s3.com/orgs/1/media/5310/5310f50f-9c8e-4035-9150-be5a1f78f21a/test.mp3", + media: &DBMedia{ + UUID_: "5310f50f-9c8e-4035-9150-be5a1f78f21a", + ContentType_: "audio/mp3", + URL_: "http://nyaruka.s3.com/orgs/1/media/5310/5310f50f-9c8e-4035-9150-be5a1f78f21a/test.mp3", + Size_: 123, + Duration_: 500, + Alternates_: []*DBMedia{ + { + UUID_: "514c552c-e585-40e2-938a-fe9450172da8", + ContentType_: "audio/mp4", + URL_: "http://nyaruka.s3.com/orgs/1/media/514c/514c552c-e585-40e2-938a-fe9450172da8/test.m4a", + Size_: 114, + Duration_: 500, + }, + }, + }, + }, + { // invalid attachment format + attachment: "foo", + err: "invalid attachment format: foo", + }, + { + // no content type + attachment: "http://example.com/test.png", + err: "invalid attachment format: http://example.com/test.png", + }, + } + + for _, tc := range tcs { + media, err := ts.b.ResolveMedia(ctx, tc.attachment) + if tc.err != "" { + ts.EqualError(err, tc.err) + } else { + ts.NoError(err) + ts.Equal(tc.media, media) + } + } + + // check we've cached 2 media lookups + assertredis.HLen(ts.T(), ts.b.redisPool, fmt.Sprintf("media-lookups:%s", time.Now().Format("2006-01-02")), 2) +} + func TestMsgSuite(t *testing.T) { suite.Run(t, new(BackendTestSuite)) } diff --git a/backends/rapidpro/media.go b/backends/rapidpro/media.go index d84d2acad..02351a61b 100644 --- a/backends/rapidpro/media.go +++ b/backends/rapidpro/media.go @@ -9,45 +9,50 @@ import ( "github.com/nyaruka/gocommon/uuids" ) -type Media struct { - UUID_ uuids.UUID `db:"uuid"` - ContentType_ string `db:"content_type"` - URL_ string `db:"url"` - Width_ int `db:"width"` - Height_ int `db:"height"` - Duration_ int `db:"duration"` - - alternates []courier.Media +type DBMedia struct { + UUID_ uuids.UUID `db:"uuid" json:"uuid"` + ContentType_ string `db:"content_type" json:"content_type"` + URL_ string `db:"url" json:"url"` + Size_ int `db:"size" json:"size"` + Width_ int `db:"width" json:"width"` + Height_ int `db:"height" json:"height"` + Duration_ int `db:"duration" json:"duration"` + + Alternates_ []*DBMedia `json:"alternates"` } -func (m *Media) UUID() uuids.UUID { return m.UUID_ } -func (m *Media) ContentType() string { return m.ContentType_ } -func (m *Media) URL() string { return m.URL_ } -func (m *Media) Width() int { return m.Width_ } -func (m *Media) Height() int { return m.Height_ } -func (m *Media) Duration() int { return m.Duration_ } -func (m *Media) Alternates() []courier.Media { return m.alternates } +func (m *DBMedia) UUID() uuids.UUID { return m.UUID_ } +func (m *DBMedia) ContentType() string { return m.ContentType_ } +func (m *DBMedia) URL() string { return m.URL_ } +func (m *DBMedia) Size() int { return m.Size_ } +func (m *DBMedia) Width() int { return m.Width_ } +func (m *DBMedia) Height() int { return m.Height_ } +func (m *DBMedia) Duration() int { return m.Duration_ } +func (m *DBMedia) Alternates() []courier.Media { + as := make([]courier.Media, len(m.Alternates_)) + for i, alt := range m.Alternates_ { + as[i] = alt + } + return as +} -var _ courier.Media = &Media{} +var _ courier.Media = &DBMedia{} var sqlLookupMediaFromUUID = ` -SELECT m.uuid, m.content_type, m.url, m.width, m.height, m.duration +SELECT m.uuid, m.content_type, m.url, m.size, m.width, m.height, m.duration FROM msgs_media m INNER JOIN msgs_media m0 ON m0.id = m.id OR m0.id = m.original_id WHERE m0.uuid = $1 -ORDER BY m.created_on` +ORDER BY m.id` -func lookupMediaFromUUID(ctx context.Context, db *sqlx.DB, uuid uuids.UUID) (*Media, error) { - var records []*Media +func lookupMediaFromUUID(ctx context.Context, db *sqlx.DB, uuid uuids.UUID) (*DBMedia, error) { + var records []*DBMedia err := db.SelectContext(ctx, &records, sqlLookupMediaFromUUID, uuid) if err == sql.ErrNoRows { return nil, nil } media, alternates := records[0], records[1:] - media.alternates = make([]courier.Media, len(alternates)) - for i, alt := range alternates { - media.alternates[i] = alt - } + media.Alternates_ = alternates return media, nil } diff --git a/backends/rapidpro/schema.sql b/backends/rapidpro/schema.sql index e21cbb7c0..445f12d5b 100644 --- a/backends/rapidpro/schema.sql +++ b/backends/rapidpro/schema.sql @@ -122,5 +122,20 @@ CREATE TABLE flows_flowsession ( wait_started_on timestamp with time zone ); +DROP TABLE IF EXISTS msgs_media CASCADE; +CREATE TABLE IF NOT EXISTS msgs_media ( + id serial primary key, + uuid uuid NOT NULL, + org_id integer NOT NULL, + content_type character varying(255) NOT NULL, + url character varying(2048) NOT NULL, + name character varying(255) NOT NULL, + size integer NOT NULL, + duration integer NOT NULL, + width integer NOT NULL, + height integer NOT NULL, + original_id integer +); + GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO courier; GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO courier; \ No newline at end of file diff --git a/backends/rapidpro/testdata.sql b/backends/rapidpro/testdata.sql index 1a59d6609..42f42bd08 100644 --- a/backends/rapidpro/testdata.sql +++ b/backends/rapidpro/testdata.sql @@ -53,6 +53,13 @@ INSERT INTO msgs_msg("id", "text", "high_priority", "created_on", "modified_on", VALUES(10002, 'test message incoming', True, now(), now(), now(), now(), 'I', 'P', 'V', 1, 0, now(), 'ext2', 10, 100, 1000, 1); +INSERT INTO msgs_media("id", "uuid", "org_id", "content_type", "url", "name", "size", "duration", "width", "height", "original_id") + VALUES(100, 'ec6972be-809c-4c8d-be59-ba9dbd74c977', 1, 'image/jpeg', 'http://nyaruka.s3.com/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg', 'test.jpg', 123, 0, 1024, 768, NULL); +INSERT INTO msgs_media("id", "uuid", "org_id", "content_type", "url", "name", "size", "duration", "width", "height", "original_id") + VALUES(101, '5310f50f-9c8e-4035-9150-be5a1f78f21a', 1, 'audio/mp3', 'http://nyaruka.s3.com/orgs/1/media/5310/5310f50f-9c8e-4035-9150-be5a1f78f21a/test.mp3', 'test.mp3', 123, 500, 0, 0, NULL); +INSERT INTO msgs_media("id", "uuid", "org_id", "content_type", "url", "name", "size", "duration", "width", "height", "original_id") + VALUES(102, '514c552c-e585-40e2-938a-fe9450172da8', 1, 'audio/mp4', 'http://nyaruka.s3.com/orgs/1/media/514c/514c552c-e585-40e2-938a-fe9450172da8/test.m4a', 'test.m4a', 114, 500, 0, 0, 101); + /** Simple session */ DELETE from flows_flowsession; INSERT INTO flows_flowsession("id", "status", "wait_started_on") diff --git a/go.mod b/go.mod index e60c4a6d7..317c7694d 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/nyaruka/ezconf v0.2.1 github.com/nyaruka/gocommon v1.24.1 github.com/nyaruka/null v1.2.0 - github.com/nyaruka/redisx v0.2.1 + github.com/nyaruka/redisx v0.2.2 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.0 diff --git a/go.sum b/go.sum index 929219873..6d22130c3 100644 --- a/go.sum +++ b/go.sum @@ -84,8 +84,8 @@ github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= github.com/nyaruka/null v1.2.0/go.mod h1:HSAFbLNOaEhHnoU0VCveCPz0GDtJ3GEtFWhvnBNkhPE= github.com/nyaruka/phonenumbers v1.1.0 h1:OvNAOAl4A9a2kNpzziITbUVH4bBBeKHkHl0llPmkxaA= github.com/nyaruka/phonenumbers v1.1.0/go.mod h1:cGaEsOrLjIL0iKGqJR5Rfywy86dSkbApEpXuM9KySNA= -github.com/nyaruka/redisx v0.2.1 h1:BavpQRCsK5xV2uxPdJJ26yVmjSo+q6bdjWqeNNf0s5w= -github.com/nyaruka/redisx v0.2.1/go.mod h1:cdbAm4y/+oFWu7qFzH2ERPeqRXJC2CtgRhwcBacM4Oc= +github.com/nyaruka/redisx v0.2.2 h1:OAJ4g1So2opn6O5akDWEWiDWgEOvPMKU10EUCG/Nv9Y= +github.com/nyaruka/redisx v0.2.2/go.mod h1:cdbAm4y/+oFWu7qFzH2ERPeqRXJC2CtgRhwcBacM4Oc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/test.go b/test.go index f7c1ab497..e3cd0000d 100644 --- a/test.go +++ b/test.go @@ -3,7 +3,6 @@ package courier import ( "context" "encoding/json" - "errors" "fmt" "log" "os" @@ -17,6 +16,7 @@ import ( "github.com/gomodule/redigo/redis" _ "github.com/lib/pq" // postgres driver + "github.com/pkg/errors" ) //----------------------------------------------------------------------------- @@ -28,7 +28,7 @@ type MockBackend struct { channels map[ChannelUUID]Channel channelsByAddress map[ChannelAddress]Channel contacts map[urns.URN]Contact - media map[string]Media + media map[string]Media // url -> Media queueMsgs []Msg errorOnQueue bool @@ -116,6 +116,11 @@ func (mb *MockBackend) GetLastContactName() string { return mb.lastContactName } +// MockMedia adds the given media to the mocked backend +func (mb *MockBackend) MockMedia(media Media) { + mb.media[media.URL()] = media +} + // DeleteMsgWithExternalID delete a message we receive an event that it should be deleted func (mb *MockBackend) DeleteMsgWithExternalID(ctx context.Context, channel Channel, externalID string) error { return nil @@ -359,8 +364,20 @@ func (mb *MockBackend) WriteExternalIDSeen(msg Msg) { // ResolveMedia resolves the passed in media URL to a media object func (mb *MockBackend) ResolveMedia(ctx context.Context, a string) (Media, error) { - // TODO: implement - return nil, nil + // split into content-type and URL + parts := strings.SplitN(a, ":", 2) + var contentType, mediaUrl string + if len(parts) <= 1 || strings.HasPrefix(parts[1], "//") { + return nil, errors.Errorf("invalid attachment format: %s", a) + } + + contentType, mediaUrl = parts[0], parts[1] + media := mb.media[mediaUrl] + if media == nil { + return &mockMedia{contentType: contentType, url: mediaUrl}, nil + } + + return media, nil } // Health gives a string representing our health, empty for our mock @@ -743,3 +760,40 @@ func ReadFile(path string) []byte { } return d } + +//----------------------------------------------------------------------------- +// Mock media implementation +//----------------------------------------------------------------------------- + +type mockMedia struct { + uuid uuids.UUID + contentType string + url string + size int + width int + height int + duration int + alternates []Media +} + +func (m *mockMedia) UUID() uuids.UUID { return m.uuid } +func (m *mockMedia) ContentType() string { return m.contentType } +func (m *mockMedia) URL() string { return m.url } +func (m *mockMedia) Size() int { return m.size } +func (m *mockMedia) Width() int { return m.width } +func (m *mockMedia) Height() int { return m.height } +func (m *mockMedia) Duration() int { return m.duration } +func (m *mockMedia) Alternates() []Media { return m.alternates } + +func NewMockMedia(uuid uuids.UUID, contentType, url string, size, width, height, duration int, alternates []Media) Media { + return &mockMedia{ + uuid: uuid, + contentType: contentType, + url: url, + size: size, + width: width, + height: height, + duration: duration, + alternates: alternates, + } +} From fec63092da53a6cdf71b996b92f153aa9d63a9d0 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 3 Aug 2022 11:47:30 -0500 Subject: [PATCH 039/294] Update CHANGELOG.md for v7.5.5 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc27d6269..8707df10b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.5 +---------- + * Switch to using null.Map instead of utils.NullMap + v7.5.4 ---------- * Add AWS Cred Chain support for S3 From 3c15d4eb9c3a93766d0d3fc9653b50c334a89c9c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 3 Aug 2022 15:34:37 -0500 Subject: [PATCH 040/294] Add handler support for resolving media --- backend.go | 2 - backends/rapidpro/backend.go | 30 +++---- backends/rapidpro/backend_test.go | 66 +++++++-------- backends/rapidpro/media.go | 5 +- handlers/media.go | 134 ++++++++++++++++++++++++++++++ handlers/media_test.go | 133 +++++++++++++++++++++++++++++ test.go | 17 +--- 7 files changed, 313 insertions(+), 74 deletions(-) create mode 100644 handlers/media.go create mode 100644 handlers/media_test.go diff --git a/backend.go b/backend.go index 0ec093c6e..0f21ad515 100644 --- a/backend.go +++ b/backend.go @@ -7,7 +7,6 @@ import ( "github.com/gomodule/redigo/redis" "github.com/nyaruka/gocommon/urns" - "github.com/nyaruka/gocommon/uuids" ) // BackendConstructorFunc defines a function to create a particular backend type @@ -106,7 +105,6 @@ type Backend interface { // Media is a resolved media object that can be used as a message attachment type Media interface { - UUID() uuids.UUID ContentType() string URL() string Size() int diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index d1a6b890f..8b9e78103 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -410,28 +410,18 @@ func (b *backend) WriteExternalIDSeen(msg courier.Msg) { writeExternalIDSeen(b, msg) } -// ResolveMedia resolves the passed in attachment (content_type:url) to a media object -func (b *backend) ResolveMedia(ctx context.Context, a string) (courier.Media, error) { - // split into content-type and URL - parts := strings.SplitN(a, ":", 2) - var contentType, mediaUrl string - if len(parts) <= 1 || strings.HasPrefix(parts[1], "//") { - return nil, errors.Errorf("invalid attachment format: %s", a) - } - - contentType, mediaUrl = parts[0], parts[1] - stub := &DBMedia{URL_: mediaUrl, ContentType_: contentType} - - // if we can't parse the URL or the hostname isn't our media domain, return stub +// ResolveMedia resolves the passed in attachment URL to a media object +func (b *backend) ResolveMedia(ctx context.Context, mediaUrl string) (courier.Media, error) { u, err := url.Parse(mediaUrl) - if err != nil || u.Hostname() != b.config.MediaDomain { - return stub, nil + if err != nil { + return nil, errors.Errorf("error parsing media URL: %s", mediaUrl) } - // likewise if path doesn't contain a UUID, return stub mediaUUID := uuidRegex.FindString(u.Path) - if mediaUUID == "" { - return stub, nil + + // if hostname isn't our media domain, or path doesn't contain a UUID, don't try to resolve + if u.Hostname() != b.config.MediaDomain || mediaUUID == "" { + return nil, nil } unlock := b.mediaMutexes.Lock(mediaUUID) @@ -458,9 +448,9 @@ func (b *backend) ResolveMedia(ctx context.Context, a string) (courier.Media, er b.mediaCache.Set(rc, mediaUUID, string(jsonx.MustMarshal(media))) } - // if we didn't find a media record or the one we found doesn't match the URL, return stub + // if we found a media record but it doesn't match the URL, don't use it if media == nil || media.URL() != mediaUrl { - return stub, nil + return nil, nil } return media, nil diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index c0f1f51d9..712c1fe9d 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -1281,24 +1281,12 @@ func (ts *BackendTestSuite) TestResolveMedia() { ctx := context.Background() tcs := []struct { - attachment string - media *DBMedia - err string + url string + media courier.Media + err string }{ - { // user entered image URL - attachment: "image:https://example.com/test.png", - media: &DBMedia{ContentType_: "image", URL_: "https://example.com/test.png"}, - }, - { // user entered audio URL - attachment: "audio:https://example.com/test.mp3", - media: &DBMedia{ContentType_: "audio", URL_: "https://example.com/test.mp3"}, - }, - { // user entered unparseable URL - attachment: "video:https::/example.com/test.mp4", - media: &DBMedia{ContentType_: "video", URL_: "https::/example.com/test.mp4"}, - }, - { // image upload - attachment: "image/jpeg:http://nyaruka.s3.com/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg", + { // image upload that can be resolved + url: "http://nyaruka.s3.com/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg", media: &DBMedia{ UUID_: "ec6972be-809c-4c8d-be59-ba9dbd74c977", ContentType_: "image/jpeg", @@ -1310,7 +1298,7 @@ func (ts *BackendTestSuite) TestResolveMedia() { }, }, { // same image upload, this time from cache - attachment: "image/jpeg:http://nyaruka.s3.com/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg", + url: "http://nyaruka.s3.com/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg", media: &DBMedia{ UUID_: "ec6972be-809c-4c8d-be59-ba9dbd74c977", ContentType_: "image/jpeg", @@ -1321,15 +1309,24 @@ func (ts *BackendTestSuite) TestResolveMedia() { Alternates_: []*DBMedia{}, }, }, + { // image upload that can't be resolved + url: "http://nyaruka.s3.com/orgs/1/media/9790/97904d00-1e64-4f92-b4a0-156e21239d24/test.jpg", + media: nil, + }, + { // image upload that can't be resolved, this time from cache + url: "http://nyaruka.s3.com/orgs/1/media/9790/97904d00-1e64-4f92-b4a0-156e21239d24/test.jpg", + media: nil, + }, { // image upload but with wrong domain - attachment: "image/jpeg:http://temba.s2.com/orgs/1/media/f328/f32801ec-433a-4862-978d-56c1823b92b2/test.jpg", - media: &DBMedia{ - ContentType_: "image/jpeg", - URL_: "http://temba.s2.com/orgs/1/media/f328/f32801ec-433a-4862-978d-56c1823b92b2/test.jpg", - }, + url: "http://temba.s2.com/orgs/1/media/f328/f32801ec-433a-4862-978d-56c1823b92b2/test.jpg", + media: nil, + }, + { // image upload but no UUID in URL + url: "http://nyaruka.s3.com/orgs/1/media/test.jpg", + media: nil, }, { // audio upload - attachment: "audio/mp3:http://nyaruka.s3.com/orgs/1/media/5310/5310f50f-9c8e-4035-9150-be5a1f78f21a/test.mp3", + url: "http://nyaruka.s3.com/orgs/1/media/5310/5310f50f-9c8e-4035-9150-be5a1f78f21a/test.mp3", media: &DBMedia{ UUID_: "5310f50f-9c8e-4035-9150-be5a1f78f21a", ContentType_: "audio/mp3", @@ -1347,29 +1344,24 @@ func (ts *BackendTestSuite) TestResolveMedia() { }, }, }, - { // invalid attachment format - attachment: "foo", - err: "invalid attachment format: foo", - }, - { - // no content type - attachment: "http://example.com/test.png", - err: "invalid attachment format: http://example.com/test.png", + { // user entered unparseable URL + url: "::::", + err: "error parsing media URL: ::::", }, } for _, tc := range tcs { - media, err := ts.b.ResolveMedia(ctx, tc.attachment) + media, err := ts.b.ResolveMedia(ctx, tc.url) if tc.err != "" { ts.EqualError(err, tc.err) } else { - ts.NoError(err) - ts.Equal(tc.media, media) + ts.NoError(err, "unexpected error for url '%s'", tc.url) + ts.Equal(tc.media, media, "media mismatch for url '%s'", tc.url) } } - // check we've cached 2 media lookups - assertredis.HLen(ts.T(), ts.b.redisPool, fmt.Sprintf("media-lookups:%s", time.Now().Format("2006-01-02")), 2) + // check we've cached 3 media lookups + assertredis.HLen(ts.T(), ts.b.redisPool, fmt.Sprintf("media-lookups:%s", time.Now().Format("2006-01-02")), 3) } func TestMsgSuite(t *testing.T) { diff --git a/backends/rapidpro/media.go b/backends/rapidpro/media.go index 02351a61b..be15ee227 100644 --- a/backends/rapidpro/media.go +++ b/backends/rapidpro/media.go @@ -48,7 +48,10 @@ ORDER BY m.id` func lookupMediaFromUUID(ctx context.Context, db *sqlx.DB, uuid uuids.UUID) (*DBMedia, error) { var records []*DBMedia err := db.SelectContext(ctx, &records, sqlLookupMediaFromUUID, uuid) - if err == sql.ErrNoRows { + if err != nil && err != sql.ErrNoRows { + return nil, err + } + if len(records) == 0 { return nil, nil } diff --git a/handlers/media.go b/handlers/media.go new file mode 100644 index 000000000..67b33f5d5 --- /dev/null +++ b/handlers/media.go @@ -0,0 +1,134 @@ +package handlers + +import ( + "context" + "strings" + + "github.com/nyaruka/courier" + "github.com/pkg/errors" +) + +type MediaType string + +const ( + MediaTypeImage MediaType = "image" + MediaTypeAudio MediaType = "audio" + MediaTypeVideo MediaType = "video" +) + +// Attachment is a resolved attachment +type Attachment struct { + Type MediaType + ContentType string + URL string + Media courier.Media + Thumbnail courier.Media +} + +// ResolveAttachments resolves the given attachment strings (content-type:url) into attachment objects +func ResolveAttachments(ctx context.Context, b courier.Backend, attachments []string, supportedTypes []string, allowExternal bool) ([]*Attachment, error) { + resolved := make([]*Attachment, 0, len(attachments)) + + for _, as := range attachments { + att, err := resolveAttachment(ctx, b, as, supportedTypes, allowExternal) + if err != nil { + return nil, err + } + if att != nil { + resolved = append(resolved, att) + } + } + + return resolved, nil +} + +func resolveAttachment(ctx context.Context, b courier.Backend, attachment string, supportedTypes []string, allowExternal bool) (*Attachment, error) { + // split into content-type and URL + parts := strings.SplitN(attachment, ":", 2) + if len(parts) <= 1 || strings.HasPrefix(parts[1], "//") { + return nil, errors.Errorf("invalid attachment format: %s", attachment) + } + contentType, mediaUrl := parts[0], parts[1] + + media, err := b.ResolveMedia(ctx, mediaUrl) + if err != nil { + return nil, err + } + + if media == nil { + // if the channel type allows it, we can still use the media URL without being able to resolve it + if allowExternal { + mediaType, _ := parseContentType(contentType) + return &Attachment{Type: mediaType, ContentType: contentType, URL: mediaUrl}, nil + } else { + return nil, nil + } + } + + mediaType, _ := parseContentType(media.ContentType()) + + // our candidates are the uploaded media and any alternates of the same media type + candidates := append([]courier.Media{media}, filterMediaByType(media.Alternates(), mediaType)...) + + // narrow down the candidates to the ones we support + if len(supportedTypes) > 0 { + candidates = filterMediaByContentTypes(candidates, supportedTypes) + } + + // if we have no candidates, we can't use this media + if len(candidates) == 0 { + return nil, nil + } + media = candidates[0] + + // if we have an image alternate, that can be a thumbnail + var thumbnail courier.Media + thumbnails := filterMediaByType(media.Alternates(), MediaTypeImage) + if len(thumbnails) > 0 { + thumbnail = thumbnails[0] + } + + return &Attachment{ + Type: mediaType, + ContentType: media.ContentType(), + URL: media.URL(), + Media: media, + Thumbnail: thumbnail, + }, nil +} + +func filterMediaByType(in []courier.Media, mediaType MediaType) []courier.Media { + return filterMedia(in, func(m courier.Media) bool { + mt, _ := parseContentType(m.ContentType()) + return mt == mediaType + }) +} + +func filterMediaByContentTypes(in []courier.Media, types []string) []courier.Media { + return filterMedia(in, func(m courier.Media) bool { + for _, t := range types { + if m.ContentType() == t { + return true + } + } + return false + }) +} + +func filterMedia(in []courier.Media, f func(courier.Media) bool) []courier.Media { + filtered := make([]courier.Media, 0, len(in)) + for _, m := range in { + if f(m) { + filtered = append(filtered, m) + } + } + return filtered +} + +func parseContentType(t string) (MediaType, string) { + parts := strings.SplitN(t, "/", 2) + if len(parts) == 2 { + return MediaType(parts[0]), parts[1] + } + return MediaType(parts[0]), "" +} diff --git a/handlers/media_test.go b/handlers/media_test.go new file mode 100644 index 000000000..78d063943 --- /dev/null +++ b/handlers/media_test.go @@ -0,0 +1,133 @@ +package handlers_test + +import ( + "context" + "testing" + + "github.com/nyaruka/courier" + "github.com/nyaruka/courier/handlers" + "github.com/stretchr/testify/assert" +) + +func TestResolveAttachments(t *testing.T) { + ctx := context.Background() + mb := courier.NewMockBackend() + + imageJPG := courier.NewMockMedia("image/jpeg", "http://mock.com/1234/test.jpg", 123, 640, 480, 0, nil) + + audioM4A := courier.NewMockMedia("audio/mp4", "http://mock.com/2345/test.m4a", 123, 0, 0, 200, nil) + audioMP3 := courier.NewMockMedia("audio/mp3", "http://mock.com/3456/test.mp3", 123, 0, 0, 200, []courier.Media{audioM4A}) + + thumbJPG := courier.NewMockMedia("image/jpeg", "http://mock.com/4567/test.jpg", 123, 640, 480, 0, nil) + videoMP4 := courier.NewMockMedia("video/mp4", "http://mock.com/5678/test.mp4", 123, 0, 0, 1000, []courier.Media{thumbJPG}) + + videoMOV := courier.NewMockMedia("video/quicktime", "http://mock.com/6789/test.mov", 123, 0, 0, 2000, nil) + + mb.MockMedia(imageJPG) + mb.MockMedia(audioMP3) + mb.MockMedia(videoMP4) + mb.MockMedia(videoMOV) + + tcs := []struct { + attachments []string + supportedTypes []string + allowExternal bool + resolved []*handlers.Attachment + err string + }{ + { // 0: user entered image URL + attachments: []string{"image:https://example.com/image.jpg"}, + supportedTypes: []string{"image/png"}, // ignored + allowExternal: true, + resolved: []*handlers.Attachment{ + {Type: handlers.MediaTypeImage, ContentType: "image", URL: "https://example.com/image.jpg"}, + }, + }, + { // 1: user entered image URL, external URLs not allowed + attachments: []string{"image:https://example.com/image.jpg"}, + supportedTypes: []string{"image/png"}, // ignored + allowExternal: false, + resolved: []*handlers.Attachment{}, + }, + { // 2: resolveable uploaded image URL + attachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, + supportedTypes: []string{"image/jpeg", "image/png"}, + allowExternal: true, + resolved: []*handlers.Attachment{ + {Type: handlers.MediaTypeImage, ContentType: "image/jpeg", URL: "http://mock.com/1234/test.jpg", Media: imageJPG, Thumbnail: nil}, + }, + }, + { // 3: unresolveable uploaded image URL + attachments: []string{"image/jpeg:http://mock.com/9876/gone.jpg"}, + supportedTypes: []string{"image/jpeg", "image/png"}, + allowExternal: true, + resolved: []*handlers.Attachment{ + {Type: handlers.MediaTypeImage, ContentType: "image/jpeg", URL: "http://mock.com/9876/gone.jpg", Media: nil, Thumbnail: nil}, + }, + }, + { // 4: unresolveable uploaded image URL, external URLs not allowed + attachments: []string{"image/jpeg:http://mock.com/9876/gone.jpg"}, + supportedTypes: []string{"image/jpeg", "image/png"}, + allowExternal: false, + resolved: []*handlers.Attachment{}, + }, + { // 5: resolveable uploaded image URL, type not in supported types + attachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, + supportedTypes: []string{"image/png", "audio/mp4"}, + allowExternal: true, + resolved: []*handlers.Attachment{}, + }, + { // 6: resolveable uploaded audio URL, type in supported types + attachments: []string{"audio/mp3:http://mock.com/3456/test.mp3"}, + supportedTypes: []string{"image/jpeg", "audio/mp3", "audio/mp4"}, + allowExternal: true, + resolved: []*handlers.Attachment{ + {Type: handlers.MediaTypeAudio, ContentType: "audio/mp3", URL: "http://mock.com/3456/test.mp3", Media: audioMP3, Thumbnail: nil}, + }, + }, + { // 7: resolveable uploaded audio URL, type not in supported types, but has alternate + attachments: []string{"audio/mp3:http://mock.com/3456/test.mp3"}, + supportedTypes: []string{"image/jpeg", "audio/mp4"}, + allowExternal: true, + resolved: []*handlers.Attachment{ + {Type: handlers.MediaTypeAudio, ContentType: "audio/mp4", URL: "http://mock.com/2345/test.m4a", Media: audioM4A, Thumbnail: nil}, + }, + }, + { // 8: resolveable uploaded video URL, has thumbnail + attachments: []string{"video/mp4:http://mock.com/5678/test.mp4"}, + supportedTypes: []string{"image/jpeg", "audio/mp4", "video/mp4"}, + allowExternal: true, + resolved: []*handlers.Attachment{ + {Type: handlers.MediaTypeVideo, ContentType: "video/mp4", URL: "http://mock.com/5678/test.mp4", Media: videoMP4, Thumbnail: thumbJPG}, + }, + }, + { // 9: resolveable uploaded video URL, no thumbnail + attachments: []string{"video/quicktime:http://mock.com/6789/test.mov"}, + supportedTypes: []string{"image/jpeg", "audio/mp4", "video/mp4", "video/quicktime"}, + allowExternal: true, + resolved: []*handlers.Attachment{ + {Type: handlers.MediaTypeVideo, ContentType: "video/quicktime", URL: "http://mock.com/6789/test.mov", Media: videoMOV, Thumbnail: nil}, + }, + }, + { // 10: invalid attachment format + attachments: []string{"image"}, + supportedTypes: []string{"image/jpeg"}, + err: "invalid attachment format: image", + }, + { // 11: invalid attachment format (missing content type) + attachments: []string{"http://mock.com/1234/test.jpg"}, + supportedTypes: []string{"image/jpeg"}, + err: "invalid attachment format: http://mock.com/1234/test.jpg", + }, + } + + for i, tc := range tcs { + resolved, err := handlers.ResolveAttachments(ctx, mb, tc.attachments, tc.supportedTypes, tc.allowExternal) + if tc.err != "" { + assert.EqualError(t, err, tc.err, "expected error for test %d", i) + } else { + assert.NoError(t, err, "unexpected error for test %d", i) + assert.Equal(t, tc.resolved, resolved, "mismatch for test %d", i) + } + } +} diff --git a/test.go b/test.go index e3cd0000d..95130e346 100644 --- a/test.go +++ b/test.go @@ -363,18 +363,10 @@ func (mb *MockBackend) WriteExternalIDSeen(msg Msg) { } // ResolveMedia resolves the passed in media URL to a media object -func (mb *MockBackend) ResolveMedia(ctx context.Context, a string) (Media, error) { - // split into content-type and URL - parts := strings.SplitN(a, ":", 2) - var contentType, mediaUrl string - if len(parts) <= 1 || strings.HasPrefix(parts[1], "//") { - return nil, errors.Errorf("invalid attachment format: %s", a) - } - - contentType, mediaUrl = parts[0], parts[1] +func (mb *MockBackend) ResolveMedia(ctx context.Context, mediaUrl string) (Media, error) { media := mb.media[mediaUrl] if media == nil { - return &mockMedia{contentType: contentType, url: mediaUrl}, nil + return nil, nil } return media, nil @@ -766,7 +758,6 @@ func ReadFile(path string) []byte { //----------------------------------------------------------------------------- type mockMedia struct { - uuid uuids.UUID contentType string url string size int @@ -776,7 +767,6 @@ type mockMedia struct { alternates []Media } -func (m *mockMedia) UUID() uuids.UUID { return m.uuid } func (m *mockMedia) ContentType() string { return m.contentType } func (m *mockMedia) URL() string { return m.url } func (m *mockMedia) Size() int { return m.size } @@ -785,9 +775,8 @@ func (m *mockMedia) Height() int { return m.height } func (m *mockMedia) Duration() int { return m.duration } func (m *mockMedia) Alternates() []Media { return m.alternates } -func NewMockMedia(uuid uuids.UUID, contentType, url string, size, width, height, duration int, alternates []Media) Media { +func NewMockMedia(contentType, url string, size, width, height, duration int, alternates []Media) Media { return &mockMedia{ - uuid: uuid, contentType: contentType, url: url, size: size, From 61686348b0caddd879837a8a37b17f9aded07a03 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 4 Aug 2022 11:29:11 -0500 Subject: [PATCH 041/294] Fix rocketchat handler dot-import causing conflict with handlers.Attachment --- handlers/rocketchat/rocketchat_test.go | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/handlers/rocketchat/rocketchat_test.go b/handlers/rocketchat/rocketchat_test.go index 501abd196..facd87537 100644 --- a/handlers/rocketchat/rocketchat_test.go +++ b/handlers/rocketchat/rocketchat_test.go @@ -1,10 +1,11 @@ package rocketchat import ( - "github.com/nyaruka/courier" - . "github.com/nyaruka/courier/handlers" "net/http/httptest" "testing" + + "github.com/nyaruka/courier" + "github.com/nyaruka/courier/handlers" ) const ( @@ -47,7 +48,7 @@ const attachmentMsg = `{ "attachments": [{"type": "image/jpg", "url": "https://link.to/image.jpg"}] }` -var testCases = []ChannelHandleTestCase{ +var testCases = []handlers.ChannelHandleTestCase{ { Label: "Receive Hello Msg", URL: receiveURL, @@ -55,8 +56,8 @@ var testCases = []ChannelHandleTestCase{ "Authorization": "Token 123456789", }, Data: helloMsg, - URN: Sp("rocketchat:direct:john.doe#john.doe"), - Text: Sp("Hello World"), + URN: handlers.Sp("rocketchat:direct:john.doe#john.doe"), + Text: handlers.Sp("Hello World"), Status: 200, Response: "Accepted", }, @@ -67,8 +68,8 @@ var testCases = []ChannelHandleTestCase{ "Authorization": "Token 123456789", }, Data: attachmentMsg, - URN: Sp("rocketchat:livechat:onrMgdKbpX9Qqtvoi"), - Attachment: Sp("https://link.to/image.jpg"), + URN: handlers.Sp("rocketchat:livechat:onrMgdKbpX9Qqtvoi"), + Attachment: handlers.Sp("https://link.to/image.jpg"), Status: 200, Response: "Accepted", }, @@ -95,18 +96,18 @@ var testCases = []ChannelHandleTestCase{ } func TestHandler(t *testing.T) { - RunChannelTestCases(t, testChannels, newHandler(), testCases) + handlers.RunChannelTestCases(t, testChannels, newHandler(), testCases) } func BenchmarkHandler(b *testing.B) { - RunChannelBenchmarks(b, testChannels, newHandler(), testCases) + handlers.RunChannelBenchmarks(b, testChannels, newHandler(), testCases) } func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { c.(*courier.MockChannel).SetConfig(configBaseURL, s.URL) } -var sendTestCases = []ChannelSendTestCase{ +var sendTestCases = []handlers.ChannelSendTestCase{ { Label: "Plain Send", Text: "Simple Message", @@ -144,5 +145,5 @@ var sendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - RunChannelSendTestCases(t, testChannels[0], newHandler(), sendTestCases, nil) + handlers.RunChannelSendTestCases(t, testChannels[0], newHandler(), sendTestCases, nil) } From 5750d08694ebe3013bd0f35bcac05904c05c5552 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 4 Aug 2022 11:33:09 -0500 Subject: [PATCH 042/294] Rename allowExternal to allowURLOnly --- handlers/media.go | 8 ++++---- handlers/media_test.go | 28 ++++++++++++++-------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/handlers/media.go b/handlers/media.go index 67b33f5d5..a7ccdf4bf 100644 --- a/handlers/media.go +++ b/handlers/media.go @@ -26,11 +26,11 @@ type Attachment struct { } // ResolveAttachments resolves the given attachment strings (content-type:url) into attachment objects -func ResolveAttachments(ctx context.Context, b courier.Backend, attachments []string, supportedTypes []string, allowExternal bool) ([]*Attachment, error) { +func ResolveAttachments(ctx context.Context, b courier.Backend, attachments []string, supportedTypes []string, allowURLOnly bool) ([]*Attachment, error) { resolved := make([]*Attachment, 0, len(attachments)) for _, as := range attachments { - att, err := resolveAttachment(ctx, b, as, supportedTypes, allowExternal) + att, err := resolveAttachment(ctx, b, as, supportedTypes, allowURLOnly) if err != nil { return nil, err } @@ -42,7 +42,7 @@ func ResolveAttachments(ctx context.Context, b courier.Backend, attachments []st return resolved, nil } -func resolveAttachment(ctx context.Context, b courier.Backend, attachment string, supportedTypes []string, allowExternal bool) (*Attachment, error) { +func resolveAttachment(ctx context.Context, b courier.Backend, attachment string, supportedTypes []string, allowURLOnly bool) (*Attachment, error) { // split into content-type and URL parts := strings.SplitN(attachment, ":", 2) if len(parts) <= 1 || strings.HasPrefix(parts[1], "//") { @@ -57,7 +57,7 @@ func resolveAttachment(ctx context.Context, b courier.Backend, attachment string if media == nil { // if the channel type allows it, we can still use the media URL without being able to resolve it - if allowExternal { + if allowURLOnly { mediaType, _ := parseContentType(contentType) return &Attachment{Type: mediaType, ContentType: contentType, URL: mediaUrl}, nil } else { diff --git a/handlers/media_test.go b/handlers/media_test.go index 78d063943..8a42e35a1 100644 --- a/handlers/media_test.go +++ b/handlers/media_test.go @@ -31,28 +31,28 @@ func TestResolveAttachments(t *testing.T) { tcs := []struct { attachments []string supportedTypes []string - allowExternal bool + allowURLOnly bool resolved []*handlers.Attachment err string }{ { // 0: user entered image URL attachments: []string{"image:https://example.com/image.jpg"}, supportedTypes: []string{"image/png"}, // ignored - allowExternal: true, + allowURLOnly: true, resolved: []*handlers.Attachment{ {Type: handlers.MediaTypeImage, ContentType: "image", URL: "https://example.com/image.jpg"}, }, }, - { // 1: user entered image URL, external URLs not allowed + { // 1: user entered image URL, URL only attachments not allowed attachments: []string{"image:https://example.com/image.jpg"}, supportedTypes: []string{"image/png"}, // ignored - allowExternal: false, + allowURLOnly: false, resolved: []*handlers.Attachment{}, }, { // 2: resolveable uploaded image URL attachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, supportedTypes: []string{"image/jpeg", "image/png"}, - allowExternal: true, + allowURLOnly: true, resolved: []*handlers.Attachment{ {Type: handlers.MediaTypeImage, ContentType: "image/jpeg", URL: "http://mock.com/1234/test.jpg", Media: imageJPG, Thumbnail: nil}, }, @@ -60,27 +60,27 @@ func TestResolveAttachments(t *testing.T) { { // 3: unresolveable uploaded image URL attachments: []string{"image/jpeg:http://mock.com/9876/gone.jpg"}, supportedTypes: []string{"image/jpeg", "image/png"}, - allowExternal: true, + allowURLOnly: true, resolved: []*handlers.Attachment{ {Type: handlers.MediaTypeImage, ContentType: "image/jpeg", URL: "http://mock.com/9876/gone.jpg", Media: nil, Thumbnail: nil}, }, }, - { // 4: unresolveable uploaded image URL, external URLs not allowed + { // 4: unresolveable uploaded image URL, URL only attachments not allowed attachments: []string{"image/jpeg:http://mock.com/9876/gone.jpg"}, supportedTypes: []string{"image/jpeg", "image/png"}, - allowExternal: false, + allowURLOnly: false, resolved: []*handlers.Attachment{}, }, { // 5: resolveable uploaded image URL, type not in supported types attachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, supportedTypes: []string{"image/png", "audio/mp4"}, - allowExternal: true, + allowURLOnly: true, resolved: []*handlers.Attachment{}, }, { // 6: resolveable uploaded audio URL, type in supported types attachments: []string{"audio/mp3:http://mock.com/3456/test.mp3"}, supportedTypes: []string{"image/jpeg", "audio/mp3", "audio/mp4"}, - allowExternal: true, + allowURLOnly: true, resolved: []*handlers.Attachment{ {Type: handlers.MediaTypeAudio, ContentType: "audio/mp3", URL: "http://mock.com/3456/test.mp3", Media: audioMP3, Thumbnail: nil}, }, @@ -88,7 +88,7 @@ func TestResolveAttachments(t *testing.T) { { // 7: resolveable uploaded audio URL, type not in supported types, but has alternate attachments: []string{"audio/mp3:http://mock.com/3456/test.mp3"}, supportedTypes: []string{"image/jpeg", "audio/mp4"}, - allowExternal: true, + allowURLOnly: true, resolved: []*handlers.Attachment{ {Type: handlers.MediaTypeAudio, ContentType: "audio/mp4", URL: "http://mock.com/2345/test.m4a", Media: audioM4A, Thumbnail: nil}, }, @@ -96,7 +96,7 @@ func TestResolveAttachments(t *testing.T) { { // 8: resolveable uploaded video URL, has thumbnail attachments: []string{"video/mp4:http://mock.com/5678/test.mp4"}, supportedTypes: []string{"image/jpeg", "audio/mp4", "video/mp4"}, - allowExternal: true, + allowURLOnly: true, resolved: []*handlers.Attachment{ {Type: handlers.MediaTypeVideo, ContentType: "video/mp4", URL: "http://mock.com/5678/test.mp4", Media: videoMP4, Thumbnail: thumbJPG}, }, @@ -104,7 +104,7 @@ func TestResolveAttachments(t *testing.T) { { // 9: resolveable uploaded video URL, no thumbnail attachments: []string{"video/quicktime:http://mock.com/6789/test.mov"}, supportedTypes: []string{"image/jpeg", "audio/mp4", "video/mp4", "video/quicktime"}, - allowExternal: true, + allowURLOnly: true, resolved: []*handlers.Attachment{ {Type: handlers.MediaTypeVideo, ContentType: "video/quicktime", URL: "http://mock.com/6789/test.mov", Media: videoMOV, Thumbnail: nil}, }, @@ -122,7 +122,7 @@ func TestResolveAttachments(t *testing.T) { } for i, tc := range tcs { - resolved, err := handlers.ResolveAttachments(ctx, mb, tc.attachments, tc.supportedTypes, tc.allowExternal) + resolved, err := handlers.ResolveAttachments(ctx, mb, tc.attachments, tc.supportedTypes, tc.allowURLOnly) if tc.err != "" { assert.EqualError(t, err, tc.err, "expected error for test %d", i) } else { From 903af6a9bec3b63a8186c9cafed455d8723b8487 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 4 Aug 2022 11:47:36 -0500 Subject: [PATCH 043/294] Convert telegram handler to use ResolveAttachments --- handlers/media.go | 7 ++++--- handlers/telegram/telegram.go | 36 ++++++++++++++++++----------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/handlers/media.go b/handlers/media.go index a7ccdf4bf..554e2a62c 100644 --- a/handlers/media.go +++ b/handlers/media.go @@ -11,9 +11,10 @@ import ( type MediaType string const ( - MediaTypeImage MediaType = "image" - MediaTypeAudio MediaType = "audio" - MediaTypeVideo MediaType = "video" + MediaTypeImage MediaType = "image" + MediaTypeAudio MediaType = "audio" + MediaTypeVideo MediaType = "video" + MediaTypeApplication MediaType = "application" ) // Attachment is a resolved attachment diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index b6b8cd013..6e740db46 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -187,9 +187,14 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat return nil, fmt.Errorf("invalid auth token config") } + attachments, err := handlers.ResolveAttachments(ctx, h.Backend(), msg.Attachments(), nil, true) + if err != nil { + return nil, errors.Wrap(err, "error resolving attachments") + } + // we only caption if there is only a single attachment caption := "" - if len(msg.Attachments()) == 1 { + if len(attachments) == 1 { caption = msg.Text() } @@ -209,7 +214,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat // if we have text, send that if we aren't sending it as a caption if msg.Text() != "" && caption == "" { var msgKeyBoard *ReplyKeyboardMarkup - if len(msg.Attachments()) == 0 { + if len(attachments) == 0 { msgKeyBoard = keyboard } @@ -232,18 +237,17 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } // send each attachment - for i, attachment := range msg.Attachments() { + for i, attachment := range attachments { var attachmentKeyBoard *ReplyKeyboardMarkup if i == len(msg.Attachments())-1 { attachmentKeyBoard = keyboard } - mediaType, mediaURL := handlers.SplitAttachment(attachment) - switch strings.Split(mediaType, "/")[0] { - case "image": + switch attachment.Type { + case handlers.MediaTypeImage: form := url.Values{ "chat_id": []string{msg.URN().Path()}, - "photo": []string{mediaURL}, + "photo": []string{attachment.URL}, "caption": []string{caption}, } externalID, log, botBlocked, err := h.sendMsgPart(msg, authToken, "sendPhoto", form, attachmentKeyBoard) @@ -257,10 +261,10 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat status.SetExternalID(externalID) hasError = err != nil - case "video": + case handlers.MediaTypeVideo: form := url.Values{ "chat_id": []string{msg.URN().Path()}, - "video": []string{mediaURL}, + "video": []string{attachment.URL}, "caption": []string{caption}, } externalID, log, botBlocked, err := h.sendMsgPart(msg, authToken, "sendVideo", form, attachmentKeyBoard) @@ -274,10 +278,10 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat status.SetExternalID(externalID) hasError = err != nil - case "audio": + case handlers.MediaTypeAudio: form := url.Values{ "chat_id": []string{msg.URN().Path()}, - "audio": []string{mediaURL}, + "audio": []string{attachment.URL}, "caption": []string{caption}, } externalID, log, botBlocked, err := h.sendMsgPart(msg, authToken, "sendAudio", form, attachmentKeyBoard) @@ -291,10 +295,10 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat status.SetExternalID(externalID) hasError = err != nil - case "application": + case handlers.MediaTypeApplication: form := url.Values{ "chat_id": []string{msg.URN().Path()}, - "document": []string{mediaURL}, + "document": []string{attachment.URL}, "caption": []string{caption}, } externalID, log, botBlocked, err := h.sendMsgPart(msg, authToken, "sendDocument", form, attachmentKeyBoard) @@ -309,12 +313,10 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat hasError = err != nil default: - status.AddLog(courier.NewChannelLog("Unknown media type: "+mediaType, msg.Channel(), msg.ID(), "", "", courier.NilStatusCode, - "", "", time.Duration(0), fmt.Errorf("unknown media type: %s", mediaType))) + status.AddLog(courier.NewChannelLog("Unknown attachment content type: "+attachment.ContentType, msg.Channel(), msg.ID(), "", "", courier.NilStatusCode, + "", "", time.Duration(0), fmt.Errorf("unknown attachment content type: %s", attachment.ContentType))) hasError = true - } - } if !hasError { From fa4e47c3ffa76ed39e307d601b6cd1bfcaa30ec7 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 4 Aug 2022 12:11:50 -0500 Subject: [PATCH 044/294] Replace supportedTypes string list with struct that also contains MaxBytes per media type --- handlers/media.go | 25 ++++++-- handlers/media_test.go | 112 ++++++++++++++++++---------------- handlers/telegram/telegram.go | 10 ++- 3 files changed, 88 insertions(+), 59 deletions(-) diff --git a/handlers/media.go b/handlers/media.go index 554e2a62c..22de2106f 100644 --- a/handlers/media.go +++ b/handlers/media.go @@ -17,6 +17,11 @@ const ( MediaTypeApplication MediaType = "application" ) +type MediaTypeSupport struct { + Types []string + MaxBytes int +} + // Attachment is a resolved attachment type Attachment struct { Type MediaType @@ -27,11 +32,11 @@ type Attachment struct { } // ResolveAttachments resolves the given attachment strings (content-type:url) into attachment objects -func ResolveAttachments(ctx context.Context, b courier.Backend, attachments []string, supportedTypes []string, allowURLOnly bool) ([]*Attachment, error) { +func ResolveAttachments(ctx context.Context, b courier.Backend, attachments []string, support map[MediaType]MediaTypeSupport, allowURLOnly bool) ([]*Attachment, error) { resolved := make([]*Attachment, 0, len(attachments)) for _, as := range attachments { - att, err := resolveAttachment(ctx, b, as, supportedTypes, allowURLOnly) + att, err := resolveAttachment(ctx, b, as, support, allowURLOnly) if err != nil { return nil, err } @@ -43,7 +48,7 @@ func ResolveAttachments(ctx context.Context, b courier.Backend, attachments []st return resolved, nil } -func resolveAttachment(ctx context.Context, b courier.Backend, attachment string, supportedTypes []string, allowURLOnly bool) (*Attachment, error) { +func resolveAttachment(ctx context.Context, b courier.Backend, attachment string, support map[MediaType]MediaTypeSupport, allowURLOnly bool) (*Attachment, error) { // split into content-type and URL parts := strings.SplitN(attachment, ":", 2) if len(parts) <= 1 || strings.HasPrefix(parts[1], "//") { @@ -67,13 +72,19 @@ func resolveAttachment(ctx context.Context, b courier.Backend, attachment string } mediaType, _ := parseContentType(media.ContentType()) + mediaSupport := support[mediaType] // our candidates are the uploaded media and any alternates of the same media type candidates := append([]courier.Media{media}, filterMediaByType(media.Alternates(), mediaType)...) // narrow down the candidates to the ones we support - if len(supportedTypes) > 0 { - candidates = filterMediaByContentTypes(candidates, supportedTypes) + if len(mediaSupport.Types) > 0 { + candidates = filterMediaByContentTypes(candidates, mediaSupport.Types) + } + + // narrow down the candidates to the ones that don't exceed our max bytes + if mediaSupport.MaxBytes > 0 { + candidates = filterMediaBySize(candidates, mediaSupport.MaxBytes) } // if we have no candidates, we can't use this media @@ -116,6 +127,10 @@ func filterMediaByContentTypes(in []courier.Media, types []string) []courier.Med }) } +func filterMediaBySize(in []courier.Media, maxBytes int) []courier.Media { + return filterMedia(in, func(m courier.Media) bool { return m.Size() <= maxBytes }) +} + func filterMedia(in []courier.Media, f func(courier.Media) bool) []courier.Media { filtered := make([]courier.Media, 0, len(in)) for _, m := range in { diff --git a/handlers/media_test.go b/handlers/media_test.go index 8a42e35a1..3296b9505 100644 --- a/handlers/media_test.go +++ b/handlers/media_test.go @@ -13,15 +13,15 @@ func TestResolveAttachments(t *testing.T) { ctx := context.Background() mb := courier.NewMockBackend() - imageJPG := courier.NewMockMedia("image/jpeg", "http://mock.com/1234/test.jpg", 123, 640, 480, 0, nil) + imageJPG := courier.NewMockMedia("image/jpeg", "http://mock.com/1234/test.jpg", 1024*1024, 640, 480, 0, nil) - audioM4A := courier.NewMockMedia("audio/mp4", "http://mock.com/2345/test.m4a", 123, 0, 0, 200, nil) - audioMP3 := courier.NewMockMedia("audio/mp3", "http://mock.com/3456/test.mp3", 123, 0, 0, 200, []courier.Media{audioM4A}) + audioM4A := courier.NewMockMedia("audio/mp4", "http://mock.com/2345/test.m4a", 1024*1024, 0, 0, 200, nil) + audioMP3 := courier.NewMockMedia("audio/mp3", "http://mock.com/3456/test.mp3", 1024*1024, 0, 0, 200, []courier.Media{audioM4A}) - thumbJPG := courier.NewMockMedia("image/jpeg", "http://mock.com/4567/test.jpg", 123, 640, 480, 0, nil) - videoMP4 := courier.NewMockMedia("video/mp4", "http://mock.com/5678/test.mp4", 123, 0, 0, 1000, []courier.Media{thumbJPG}) + thumbJPG := courier.NewMockMedia("image/jpeg", "http://mock.com/4567/test.jpg", 1024*1024, 640, 480, 0, nil) + videoMP4 := courier.NewMockMedia("video/mp4", "http://mock.com/5678/test.mp4", 1024*1024, 0, 0, 1000, []courier.Media{thumbJPG}) - videoMOV := courier.NewMockMedia("video/quicktime", "http://mock.com/6789/test.mov", 123, 0, 0, 2000, nil) + videoMOV := courier.NewMockMedia("video/quicktime", "http://mock.com/6789/test.mov", 100*1024*1024, 0, 0, 2000, nil) mb.MockMedia(imageJPG) mb.MockMedia(audioMP3) @@ -29,100 +29,106 @@ func TestResolveAttachments(t *testing.T) { mb.MockMedia(videoMOV) tcs := []struct { - attachments []string - supportedTypes []string - allowURLOnly bool - resolved []*handlers.Attachment - err string + attachments []string + mediaSupport map[handlers.MediaType]handlers.MediaTypeSupport + allowURLOnly bool + resolved []*handlers.Attachment + err string }{ { // 0: user entered image URL - attachments: []string{"image:https://example.com/image.jpg"}, - supportedTypes: []string{"image/png"}, // ignored - allowURLOnly: true, + attachments: []string{"image:https://example.com/image.jpg"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/png"}}}, // ignored + allowURLOnly: true, resolved: []*handlers.Attachment{ {Type: handlers.MediaTypeImage, ContentType: "image", URL: "https://example.com/image.jpg"}, }, }, { // 1: user entered image URL, URL only attachments not allowed - attachments: []string{"image:https://example.com/image.jpg"}, - supportedTypes: []string{"image/png"}, // ignored - allowURLOnly: false, - resolved: []*handlers.Attachment{}, + attachments: []string{"image:https://example.com/image.jpg"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/png"}}}, // ignored + allowURLOnly: false, + resolved: []*handlers.Attachment{}, }, { // 2: resolveable uploaded image URL - attachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, - supportedTypes: []string{"image/jpeg", "image/png"}, - allowURLOnly: true, + attachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/jpeg", "image/png"}}}, + allowURLOnly: true, resolved: []*handlers.Attachment{ {Type: handlers.MediaTypeImage, ContentType: "image/jpeg", URL: "http://mock.com/1234/test.jpg", Media: imageJPG, Thumbnail: nil}, }, }, { // 3: unresolveable uploaded image URL - attachments: []string{"image/jpeg:http://mock.com/9876/gone.jpg"}, - supportedTypes: []string{"image/jpeg", "image/png"}, - allowURLOnly: true, + attachments: []string{"image/jpeg:http://mock.com/9876/gone.jpg"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/jpeg", "image/png"}}}, + allowURLOnly: true, resolved: []*handlers.Attachment{ {Type: handlers.MediaTypeImage, ContentType: "image/jpeg", URL: "http://mock.com/9876/gone.jpg", Media: nil, Thumbnail: nil}, }, }, { // 4: unresolveable uploaded image URL, URL only attachments not allowed - attachments: []string{"image/jpeg:http://mock.com/9876/gone.jpg"}, - supportedTypes: []string{"image/jpeg", "image/png"}, - allowURLOnly: false, - resolved: []*handlers.Attachment{}, + attachments: []string{"image/jpeg:http://mock.com/9876/gone.jpg"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/jpeg", "image/png"}}}, + allowURLOnly: false, + resolved: []*handlers.Attachment{}, }, { // 5: resolveable uploaded image URL, type not in supported types - attachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, - supportedTypes: []string{"image/png", "audio/mp4"}, - allowURLOnly: true, - resolved: []*handlers.Attachment{}, + attachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/png"}}}, + allowURLOnly: true, + resolved: []*handlers.Attachment{}, }, { // 6: resolveable uploaded audio URL, type in supported types - attachments: []string{"audio/mp3:http://mock.com/3456/test.mp3"}, - supportedTypes: []string{"image/jpeg", "audio/mp3", "audio/mp4"}, - allowURLOnly: true, + attachments: []string{"audio/mp3:http://mock.com/3456/test.mp3"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeAudio: {Types: []string{"audio/mp3", "audio/mp4"}}}, + allowURLOnly: true, resolved: []*handlers.Attachment{ {Type: handlers.MediaTypeAudio, ContentType: "audio/mp3", URL: "http://mock.com/3456/test.mp3", Media: audioMP3, Thumbnail: nil}, }, }, { // 7: resolveable uploaded audio URL, type not in supported types, but has alternate - attachments: []string{"audio/mp3:http://mock.com/3456/test.mp3"}, - supportedTypes: []string{"image/jpeg", "audio/mp4"}, - allowURLOnly: true, + attachments: []string{"audio/mp3:http://mock.com/3456/test.mp3"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeAudio: {Types: []string{"audio/mp4"}}}, + allowURLOnly: true, resolved: []*handlers.Attachment{ {Type: handlers.MediaTypeAudio, ContentType: "audio/mp4", URL: "http://mock.com/2345/test.m4a", Media: audioM4A, Thumbnail: nil}, }, }, { // 8: resolveable uploaded video URL, has thumbnail - attachments: []string{"video/mp4:http://mock.com/5678/test.mp4"}, - supportedTypes: []string{"image/jpeg", "audio/mp4", "video/mp4"}, - allowURLOnly: true, + attachments: []string{"video/mp4:http://mock.com/5678/test.mp4"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeVideo: {Types: []string{"video/mp4", "video/quicktime"}}}, + allowURLOnly: true, resolved: []*handlers.Attachment{ {Type: handlers.MediaTypeVideo, ContentType: "video/mp4", URL: "http://mock.com/5678/test.mp4", Media: videoMP4, Thumbnail: thumbJPG}, }, }, { // 9: resolveable uploaded video URL, no thumbnail - attachments: []string{"video/quicktime:http://mock.com/6789/test.mov"}, - supportedTypes: []string{"image/jpeg", "audio/mp4", "video/mp4", "video/quicktime"}, - allowURLOnly: true, + attachments: []string{"video/quicktime:http://mock.com/6789/test.mov"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeVideo: {Types: []string{"video/mp4", "video/quicktime"}}}, + allowURLOnly: true, resolved: []*handlers.Attachment{ {Type: handlers.MediaTypeVideo, ContentType: "video/quicktime", URL: "http://mock.com/6789/test.mov", Media: videoMOV, Thumbnail: nil}, }, }, - { // 10: invalid attachment format - attachments: []string{"image"}, - supportedTypes: []string{"image/jpeg"}, - err: "invalid attachment format: image", + { // 10: resolveable uploaded video URL, too big + attachments: []string{"video/quicktime:http://mock.com/6789/test.mov"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeVideo: {Types: []string{"video/quicktime"}, MaxBytes: 10 * 1024 * 1024}}, + allowURLOnly: true, + resolved: []*handlers.Attachment{}, }, - { // 11: invalid attachment format (missing content type) - attachments: []string{"http://mock.com/1234/test.jpg"}, - supportedTypes: []string{"image/jpeg"}, - err: "invalid attachment format: http://mock.com/1234/test.jpg", + { // 11: invalid attachment format + attachments: []string{"image"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{}, + err: "invalid attachment format: image", + }, + { // 12: invalid attachment format (missing content type) + attachments: []string{"http://mock.com/1234/test.jpg"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{}, + err: "invalid attachment format: http://mock.com/1234/test.jpg", }, } for i, tc := range tcs { - resolved, err := handlers.ResolveAttachments(ctx, mb, tc.attachments, tc.supportedTypes, tc.allowURLOnly) + resolved, err := handlers.ResolveAttachments(ctx, mb, tc.attachments, tc.mediaSupport, tc.allowURLOnly) if tc.err != "" { assert.EqualError(t, err, tc.err, "expected error for test %d", i) } else { diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index 6e740db46..593f8fe53 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -21,6 +21,14 @@ import ( var apiURL = "https://api.telegram.org" +// see https://core.telegram.org/bots/api#sending-files +var mediaSupport = map[handlers.MediaType]handlers.MediaTypeSupport{ + handlers.MediaTypeImage: {MaxBytes: 10 * 1024 * 1024}, + handlers.MediaTypeAudio: {MaxBytes: 50 * 1024 * 1024}, + handlers.MediaTypeVideo: {MaxBytes: 50 * 1024 * 1024}, + handlers.MediaTypeApplication: {Types: []string{"application/pdf"}, MaxBytes: 50 * 1024 * 1024}, +} + func init() { courier.RegisterHandler(newHandler()) } @@ -187,7 +195,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat return nil, fmt.Errorf("invalid auth token config") } - attachments, err := handlers.ResolveAttachments(ctx, h.Backend(), msg.Attachments(), nil, true) + attachments, err := handlers.ResolveAttachments(ctx, h.Backend(), msg.Attachments(), mediaSupport, true) if err != nil { return nil, errors.Wrap(err, "error resolving attachments") } From 0c6c218b0e4e7d4dee4e1f4a6910d70a054b1b6d Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 4 Aug 2022 15:38:27 -0500 Subject: [PATCH 045/294] Use httpx.DoTrace for some channels --- channel_log.go | 21 ++++++++++++++ go.mod | 2 +- go.sum | 4 +-- handlers/africastalking/africastalking.go | 9 +++--- handlers/arabiacell/arabiacell.go | 7 ++--- handlers/blackmyna/blackmyna.go | 7 ++--- handlers/bongolive/bongolive.go | 9 +++--- handlers/http.go | 35 +++++++++++++++++++++++ handlers/http_test.go | 32 +++++++++++++++++++++ handlers/telegram/telegram.go | 14 ++++----- utils/http.go | 9 ++---- 11 files changed, 115 insertions(+), 34 deletions(-) create mode 100644 handlers/http.go create mode 100644 handlers/http_test.go diff --git a/channel_log.go b/channel_log.go index 67c1cc3c0..654e4dedb 100644 --- a/channel_log.go +++ b/channel_log.go @@ -70,6 +70,27 @@ func NewChannelLogFromRR(description string, channel Channel, msgID MsgID, rr *u return log } +// NewChannelLogFromTrace creates a new channel log for the passed in channel, id, and http trace +func NewChannelLogFromTrace(description string, channel Channel, msgID MsgID, trace *httpx.Trace) *ChannelLog { + log := &ChannelLog{ + Description: description, + Channel: channel, + MsgID: msgID, + Method: trace.Request.Method, + URL: trace.Request.URL.String(), + Request: sanitizeBody(string(trace.RequestTrace)), + CreatedOn: trace.StartTime, + Elapsed: trace.EndTime.Sub(trace.StartTime), + } + + if trace.Response != nil { + log.StatusCode = trace.Response.StatusCode + log.Response = string(trace.SanitizedResponse("...")) + } + + return log +} + // NewChannelLogFromError creates a new channel log for the passed in channel, msg id and error func NewChannelLogFromError(description string, channel Channel, msgID MsgID, elapsed time.Duration, err error) *ChannelLog { log := &ChannelLog{ diff --git a/go.mod b/go.mod index 317c7694d..690b540e0 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.6 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.24.1 + github.com/nyaruka/gocommon v1.25.0 github.com/nyaruka/null v1.2.0 github.com/nyaruka/redisx v0.2.2 github.com/patrickmn/go-cache v2.1.0+incompatible diff --git a/go.sum b/go.sum index 6d22130c3..8afc61e4b 100644 --- a/go.sum +++ b/go.sum @@ -76,8 +76,8 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.24.1 h1:JiAxkDPnsGinnM35nEpyKanXUFzM8GsW+SUxlzUzGc4= -github.com/nyaruka/gocommon v1.24.1/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= +github.com/nyaruka/gocommon v1.25.0 h1:/wi16Q9qUF3NOnRgM5q/c55dRtX0xLDHu7hDU0OTeWg= +github.com/nyaruka/gocommon v1.25.0/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= diff --git a/handlers/africastalking/africastalking.go b/handlers/africastalking/africastalking.go index e196212fb..d7205a49c 100644 --- a/handlers/africastalking/africastalking.go +++ b/handlers/africastalking/africastalking.go @@ -11,7 +11,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" ) const configIsShared = "is_shared" @@ -149,24 +148,24 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus req.Header.Set("Accept", "application/json") req.Header.Set("apikey", apiKey) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - status.AddLog(courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err)) + status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) if err != nil { return status, nil } // was this request successful? - msgStatus, _ := jsonparser.GetString([]byte(rr.Body), "SMSMessageData", "Recipients", "[0]", "status") + msgStatus, _ := jsonparser.GetString(trace.ResponseBody, "SMSMessageData", "Recipients", "[0]", "status") if msgStatus != "Success" { status.SetStatus(courier.MsgErrored) return status, nil } // grab the external id if we can - externalID, _ := jsonparser.GetString([]byte(rr.Body), "SMSMessageData", "Recipients", "[0]", "messageId") + externalID, _ := jsonparser.GetString(trace.ResponseBody, "SMSMessageData", "Recipients", "[0]", "messageId") status.SetStatus(courier.MsgWired) status.SetExternalID(externalID) diff --git a/handlers/arabiacell/arabiacell.go b/handlers/arabiacell/arabiacell.go index 3c93ba53c..26301b4f9 100644 --- a/handlers/arabiacell/arabiacell.go +++ b/handlers/arabiacell/arabiacell.go @@ -10,7 +10,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" ) const ( @@ -95,10 +94,10 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/xml") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil @@ -106,7 +105,7 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus // parse our response as XML response := &mtResponse{} - err = xml.Unmarshal(rr.Body, response) + err = xml.Unmarshal(trace.ResponseBody, response) if err != nil { log.WithError("Message Send Error", err) break diff --git a/handlers/blackmyna/blackmyna.go b/handlers/blackmyna/blackmyna.go index 81f2095c1..269c17f6f 100644 --- a/handlers/blackmyna/blackmyna.go +++ b/handlers/blackmyna/blackmyna.go @@ -10,7 +10,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/pkg/errors" ) @@ -127,17 +126,17 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.SetBasicAuth(username, password) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - status.AddLog(courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err)) + status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) if err != nil { return status, nil } // get our external id - externalID, _ := jsonparser.GetString([]byte(rr.Body), "[0]", "id") + externalID, _ := jsonparser.GetString(trace.ResponseBody, "[0]", "id") if externalID == "" { return status, errors.Errorf("no external id returned in body") } diff --git a/handlers/bongolive/bongolive.go b/handlers/bongolive/bongolive.go index d862104e6..323827df2 100644 --- a/handlers/bongolive/bongolive.go +++ b/handlers/bongolive/bongolive.go @@ -10,7 +10,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/gsm7" "github.com/buger/jsonparser" @@ -164,23 +163,23 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - rr, err := utils.MakeInsecureHTTPRequest(req) + trace, err := handlers.MakeInsecureHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Send Error", err) status.AddLog(log) if err != nil { return status, nil } // was this request successful? - msgStatus, _ := jsonparser.GetString([]byte(rr.Body), "results", "[0]", "status") + msgStatus, _ := jsonparser.GetString(trace.ResponseBody, "results", "[0]", "status") if msgStatus != "0" { status.SetStatus(courier.MsgErrored) return status, nil } // grab the external id if we can - externalID, _ := jsonparser.GetString([]byte(rr.Body), "results", "[0]", "msgid") + externalID, _ := jsonparser.GetString(trace.ResponseBody, "results", "[0]", "msgid") status.SetStatus(courier.MsgWired) status.SetExternalID(externalID) diff --git a/handlers/http.go b/handlers/http.go new file mode 100644 index 000000000..e0c8ed569 --- /dev/null +++ b/handlers/http.go @@ -0,0 +1,35 @@ +package handlers + +import ( + "fmt" + "net/http" + + "github.com/nyaruka/courier/utils" + "github.com/nyaruka/gocommon/httpx" +) + +// MakeHTTPRequest makes the given request and returns the trace +func MakeHTTPRequest(req *http.Request) (*httpx.Trace, error) { + return MakeHTTPRequestWithClient(utils.GetHTTPClient(), req) +} + +// MakeInsecureHTTPRequest makes the given request using an insecure client that does not validate +// SSL certificates, and returns the trace +func MakeInsecureHTTPRequest(req *http.Request) (*httpx.Trace, error) { + return MakeHTTPRequestWithClient(utils.GetInsecureHTTPClient(), req) +} + +// MakeHTTPRequestWithClient makes the given request using the given client, and returns the trace +func MakeHTTPRequestWithClient(client *http.Client, req *http.Request) (*httpx.Trace, error) { + trace, err := httpx.DoTrace(client, req, nil, nil, 0) + if err != nil { + return nil, err + } + + // return an error if we got a non-200 status + if trace.Response != nil && trace.Response.StatusCode/100 != 2 { + return trace, fmt.Errorf("received non 200 status: %d", trace.Response.StatusCode) + } + + return trace, nil +} diff --git a/handlers/http_test.go b/handlers/http_test.go new file mode 100644 index 000000000..437a57967 --- /dev/null +++ b/handlers/http_test.go @@ -0,0 +1,32 @@ +package handlers_test + +import ( + "net/http" + "testing" + + "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/httpx" + "github.com/stretchr/testify/assert" +) + +func TestMakeHTTPRequest(t *testing.T) { + httpx.SetRequestor(httpx.NewMockRequestor(map[string][]httpx.MockResponse{ + "https://api.messages.com/send.json": { + httpx.NewMockResponse(200, nil, []byte(`{"status":"success"}`)), + httpx.NewMockResponse(400, nil, []byte(`{"status":"error"}`)), + }, + })) + defer httpx.SetRequestor(httpx.DefaultRequestor) + + req, _ := http.NewRequest("POST", "https://api.messages.com/send.json", nil) + trace, err := handlers.MakeHTTPRequest(req) + assert.NoError(t, err) + assert.Equal(t, 200, trace.Response.StatusCode) + assert.Equal(t, []byte(`{"status":"success"}`), trace.ResponseBody) + + req, _ = http.NewRequest("POST", "https://api.messages.com/send.json", nil) + trace, err = handlers.MakeHTTPRequest(req) + assert.EqualError(t, err, "received non 200 status: 400") + assert.Equal(t, 400, trace.Response.StatusCode) + assert.Equal(t, []byte(`{"status":"error"}`), trace.ResponseBody) +} diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index b6b8cd013..c52a536b6 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -156,13 +156,13 @@ func (h *handler) sendMsgPart(msg courier.Msg, token string, path string, form u } req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // build our channel log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) response := &mtResponse{} - err = json.Unmarshal(rr.Body, response) + err = json.Unmarshal(trace.ResponseBody, response) if err != nil || !response.Ok { if response.ErrorCode == 403 && response.Description == "Forbidden: bot was blocked by the user" { @@ -343,15 +343,15 @@ func (h *handler) resolveFileID(ctx context.Context, channel courier.Channel, fi courier.LogRequestError(req, channel, err) } - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) if err != nil { - log := courier.NewChannelLogFromRR("File Resolving", channel, courier.NilMsgID, rr).WithError("File Resolving Error", err) + log := courier.NewChannelLogFromTrace("File Resolving", channel, courier.NilMsgID, trace).WithError("File Resolving Error", err) h.Backend().WriteChannelLogs(ctx, []*courier.ChannelLog{log}) return "", err } // was this request successful? - ok, err := jsonparser.GetBoolean([]byte(rr.Body), "ok") + ok, err := jsonparser.GetBoolean(trace.ResponseBody, "ok") if err != nil { return "", errors.Errorf("no 'ok' in response") } @@ -361,7 +361,7 @@ func (h *handler) resolveFileID(ctx context.Context, channel courier.Channel, fi } // grab the path for our file - filePath, err := jsonparser.GetString([]byte(rr.Body), "result", "file_path") + filePath, err := jsonparser.GetString(trace.ResponseBody, "result", "file_path") if err != nil { return "", errors.Errorf("no 'result.file_path' in response") } diff --git a/utils/http.go b/utils/http.go index ae5bb780d..1406a2589 100644 --- a/utils/http.go +++ b/utils/http.go @@ -39,20 +39,17 @@ const ( RRStatusFailure RequestResponseStatus = "E" ) -// MakeInsecureHTTPRequest fires the passed in http request against a transport that does not validate -// SSL certificates. +// Deprecated: use handlers.MakeInsecureHTTPRequest instead func MakeInsecureHTTPRequest(req *http.Request) (*RequestResponse, error) { return MakeHTTPRequestWithClient(req, GetInsecureHTTPClient()) } -// MakeHTTPRequest fires the passed in http request, returning any errors encountered. RequestResponse is always set -// regardless of any errors being set +// Deprecated: use handlers.MakeHTTPRequest instead func MakeHTTPRequest(req *http.Request) (*RequestResponse, error) { return MakeHTTPRequestWithClient(req, GetHTTPClient()) } -// MakeHTTPRequestWithClient makes an HTTP request with the passed in client, returning a -// RequestResponse containing logging information gathered during the request +// Deprecated: use handlers.MakeHTTPRequestWithClient instead func MakeHTTPRequestWithClient(req *http.Request, client *http.Client) (*RequestResponse, error) { req.Header.Set("User-Agent", HTTPUserAgent) From 6c90dde18120e5166b3c76b9d077a88456b31247 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 5 Aug 2022 10:43:07 -0500 Subject: [PATCH 046/294] Add Name to Media and Attachment so channels can easily access the filename --- backend.go | 1 + backends/rapidpro/backend_test.go | 4 ++++ backends/rapidpro/media.go | 10 ++++---- backends/rapidpro/media_test.go | 39 +++++++++++++++++++++++++++++++ backends/rapidpro/schema.sql | 2 +- backends/rapidpro/testdata.sql | 12 +++++----- handlers/media.go | 16 ++++++++++++- handlers/media_test.go | 28 +++++++++++----------- test.go | 5 +++- 9 files changed, 90 insertions(+), 27 deletions(-) create mode 100644 backends/rapidpro/media_test.go diff --git a/backend.go b/backend.go index 0f21ad515..5bc891edd 100644 --- a/backend.go +++ b/backend.go @@ -105,6 +105,7 @@ type Backend interface { // Media is a resolved media object that can be used as a message attachment type Media interface { + Name() string ContentType() string URL() string Size() int diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 712c1fe9d..d16c97142 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -1289,6 +1289,7 @@ func (ts *BackendTestSuite) TestResolveMedia() { url: "http://nyaruka.s3.com/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg", media: &DBMedia{ UUID_: "ec6972be-809c-4c8d-be59-ba9dbd74c977", + Path_: "/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg", ContentType_: "image/jpeg", URL_: "http://nyaruka.s3.com/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg", Size_: 123, @@ -1301,6 +1302,7 @@ func (ts *BackendTestSuite) TestResolveMedia() { url: "http://nyaruka.s3.com/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg", media: &DBMedia{ UUID_: "ec6972be-809c-4c8d-be59-ba9dbd74c977", + Path_: "/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg", ContentType_: "image/jpeg", URL_: "http://nyaruka.s3.com/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg", Size_: 123, @@ -1329,6 +1331,7 @@ func (ts *BackendTestSuite) TestResolveMedia() { url: "http://nyaruka.s3.com/orgs/1/media/5310/5310f50f-9c8e-4035-9150-be5a1f78f21a/test.mp3", media: &DBMedia{ UUID_: "5310f50f-9c8e-4035-9150-be5a1f78f21a", + Path_: "/orgs/1/media/5310/5310f50f-9c8e-4035-9150-be5a1f78f21a/test.mp3", ContentType_: "audio/mp3", URL_: "http://nyaruka.s3.com/orgs/1/media/5310/5310f50f-9c8e-4035-9150-be5a1f78f21a/test.mp3", Size_: 123, @@ -1336,6 +1339,7 @@ func (ts *BackendTestSuite) TestResolveMedia() { Alternates_: []*DBMedia{ { UUID_: "514c552c-e585-40e2-938a-fe9450172da8", + Path_: "/orgs/1/media/514c/514c552c-e585-40e2-938a-fe9450172da8/test.m4a", ContentType_: "audio/mp4", URL_: "http://nyaruka.s3.com/orgs/1/media/514c/514c552c-e585-40e2-938a-fe9450172da8/test.m4a", Size_: 114, diff --git a/backends/rapidpro/media.go b/backends/rapidpro/media.go index be15ee227..7c2e15406 100644 --- a/backends/rapidpro/media.go +++ b/backends/rapidpro/media.go @@ -3,6 +3,7 @@ package rapidpro import ( "context" "database/sql" + "path/filepath" "github.com/jmoiron/sqlx" "github.com/nyaruka/courier" @@ -11,17 +12,18 @@ import ( type DBMedia struct { UUID_ uuids.UUID `db:"uuid" json:"uuid"` + Path_ string `db:"path" json:"path"` ContentType_ string `db:"content_type" json:"content_type"` URL_ string `db:"url" json:"url"` - Size_ int `db:"size" json:"size"` + Size_ int `db:"size" json:"size"` Width_ int `db:"width" json:"width"` Height_ int `db:"height" json:"height"` Duration_ int `db:"duration" json:"duration"` - - Alternates_ []*DBMedia `json:"alternates"` + Alternates_ []*DBMedia ` json:"alternates"` } func (m *DBMedia) UUID() uuids.UUID { return m.UUID_ } +func (m *DBMedia) Name() string { return filepath.Base(m.Path_) } func (m *DBMedia) ContentType() string { return m.ContentType_ } func (m *DBMedia) URL() string { return m.URL_ } func (m *DBMedia) Size() int { return m.Size_ } @@ -39,7 +41,7 @@ func (m *DBMedia) Alternates() []courier.Media { var _ courier.Media = &DBMedia{} var sqlLookupMediaFromUUID = ` -SELECT m.uuid, m.content_type, m.url, m.size, m.width, m.height, m.duration +SELECT m.uuid, m.path, m.content_type, m.url, m.size, m.width, m.height, m.duration FROM msgs_media m INNER JOIN msgs_media m0 ON m0.id = m.id OR m0.id = m.original_id WHERE m0.uuid = $1 diff --git a/backends/rapidpro/media_test.go b/backends/rapidpro/media_test.go new file mode 100644 index 000000000..7178dfcd5 --- /dev/null +++ b/backends/rapidpro/media_test.go @@ -0,0 +1,39 @@ +package rapidpro_test + +import ( + "encoding/json" + "testing" + + "github.com/nyaruka/courier/backends/rapidpro" + "github.com/stretchr/testify/assert" +) + +func TestDBMedia(t *testing.T) { + media1 := &rapidpro.DBMedia{ + UUID_: "5310f50f-9c8e-4035-9150-be5a1f78f21a", + Path_: "/orgs/1/media/5310/5310f50f-9c8e-4035-9150-be5a1f78f21a/test.mp3", + ContentType_: "audio/mp3", + URL_: "http://nyaruka.s3.com/orgs/1/media/5310/5310f50f-9c8e-4035-9150-be5a1f78f21a/test.mp3", + Size_: 123, + Duration_: 500, + Alternates_: []*rapidpro.DBMedia{ + { + UUID_: "514c552c-e585-40e2-938a-fe9450172da8", + Path_: "/orgs/1/media/514c/514c552c-e585-40e2-938a-fe9450172da8/test.m4a", + ContentType_: "audio/mp4", + URL_: "http://nyaruka.s3.com/orgs/1/media/514c/514c552c-e585-40e2-938a-fe9450172da8/test.m4a", + Size_: 114, + Duration_: 500, + }, + }, + } + + // test that JSON serialization and deserialization gives the same object + media1JSON, err := json.Marshal(media1) + assert.NoError(t, err) + + media2 := &rapidpro.DBMedia{} + err = json.Unmarshal(media1JSON, media2) + assert.NoError(t, err) + assert.Equal(t, media1, media2) +} diff --git a/backends/rapidpro/schema.sql b/backends/rapidpro/schema.sql index 445f12d5b..b5861a94b 100644 --- a/backends/rapidpro/schema.sql +++ b/backends/rapidpro/schema.sql @@ -129,7 +129,7 @@ CREATE TABLE IF NOT EXISTS msgs_media ( org_id integer NOT NULL, content_type character varying(255) NOT NULL, url character varying(2048) NOT NULL, - name character varying(255) NOT NULL, + path character varying(2048) NOT NULL, size integer NOT NULL, duration integer NOT NULL, width integer NOT NULL, diff --git a/backends/rapidpro/testdata.sql b/backends/rapidpro/testdata.sql index 42f42bd08..4dc118100 100644 --- a/backends/rapidpro/testdata.sql +++ b/backends/rapidpro/testdata.sql @@ -53,12 +53,12 @@ INSERT INTO msgs_msg("id", "text", "high_priority", "created_on", "modified_on", VALUES(10002, 'test message incoming', True, now(), now(), now(), now(), 'I', 'P', 'V', 1, 0, now(), 'ext2', 10, 100, 1000, 1); -INSERT INTO msgs_media("id", "uuid", "org_id", "content_type", "url", "name", "size", "duration", "width", "height", "original_id") - VALUES(100, 'ec6972be-809c-4c8d-be59-ba9dbd74c977', 1, 'image/jpeg', 'http://nyaruka.s3.com/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg', 'test.jpg', 123, 0, 1024, 768, NULL); -INSERT INTO msgs_media("id", "uuid", "org_id", "content_type", "url", "name", "size", "duration", "width", "height", "original_id") - VALUES(101, '5310f50f-9c8e-4035-9150-be5a1f78f21a', 1, 'audio/mp3', 'http://nyaruka.s3.com/orgs/1/media/5310/5310f50f-9c8e-4035-9150-be5a1f78f21a/test.mp3', 'test.mp3', 123, 500, 0, 0, NULL); -INSERT INTO msgs_media("id", "uuid", "org_id", "content_type", "url", "name", "size", "duration", "width", "height", "original_id") - VALUES(102, '514c552c-e585-40e2-938a-fe9450172da8', 1, 'audio/mp4', 'http://nyaruka.s3.com/orgs/1/media/514c/514c552c-e585-40e2-938a-fe9450172da8/test.m4a', 'test.m4a', 114, 500, 0, 0, 101); +INSERT INTO msgs_media("id", "uuid", "org_id", "content_type", "url", "path", "size", "duration", "width", "height", "original_id") + VALUES(100, 'ec6972be-809c-4c8d-be59-ba9dbd74c977', 1, 'image/jpeg', 'http://nyaruka.s3.com/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg', '/orgs/1/media/ec69/ec6972be-809c-4c8d-be59-ba9dbd74c977/test.jpg', 123, 0, 1024, 768, NULL); +INSERT INTO msgs_media("id", "uuid", "org_id", "content_type", "url", "path", "size", "duration", "width", "height", "original_id") + VALUES(101, '5310f50f-9c8e-4035-9150-be5a1f78f21a', 1, 'audio/mp3', 'http://nyaruka.s3.com/orgs/1/media/5310/5310f50f-9c8e-4035-9150-be5a1f78f21a/test.mp3', '/orgs/1/media/5310/5310f50f-9c8e-4035-9150-be5a1f78f21a/test.mp3', 123, 500, 0, 0, NULL); +INSERT INTO msgs_media("id", "uuid", "org_id", "content_type", "url", "path", "size", "duration", "width", "height", "original_id") + VALUES(102, '514c552c-e585-40e2-938a-fe9450172da8', 1, 'audio/mp4', 'http://nyaruka.s3.com/orgs/1/media/514c/514c552c-e585-40e2-938a-fe9450172da8/test.m4a', '/orgs/1/media/514c/514c552c-e585-40e2-938a-fe9450172da8/test.m4a', 114, 500, 0, 0, 101); /** Simple session */ DELETE from flows_flowsession; diff --git a/handlers/media.go b/handlers/media.go index 22de2106f..73f183418 100644 --- a/handlers/media.go +++ b/handlers/media.go @@ -2,6 +2,8 @@ package handlers import ( "context" + "net/url" + "path" "strings" "github.com/nyaruka/courier" @@ -25,6 +27,7 @@ type MediaTypeSupport struct { // Attachment is a resolved attachment type Attachment struct { Type MediaType + Name string ContentType string URL string Media courier.Media @@ -65,7 +68,8 @@ func resolveAttachment(ctx context.Context, b courier.Backend, attachment string // if the channel type allows it, we can still use the media URL without being able to resolve it if allowURLOnly { mediaType, _ := parseContentType(contentType) - return &Attachment{Type: mediaType, ContentType: contentType, URL: mediaUrl}, nil + name := filenameFromURL(mediaUrl) + return &Attachment{Type: mediaType, Name: name, ContentType: contentType, URL: mediaUrl}, nil } else { return nil, nil } @@ -102,6 +106,7 @@ func resolveAttachment(ctx context.Context, b courier.Backend, attachment string return &Attachment{ Type: mediaType, + Name: media.Name(), ContentType: media.ContentType(), URL: media.URL(), Media: media, @@ -141,6 +146,15 @@ func filterMedia(in []courier.Media, f func(courier.Media) bool) []courier.Media return filtered } +func filenameFromURL(u string) string { + name := path.Base(u) + unescaped, err := url.PathUnescape(name) + if err == nil { + return unescaped + } + return name +} + func parseContentType(t string) (MediaType, string) { parts := strings.SplitN(t, "/", 2) if len(parts) == 2 { diff --git a/handlers/media_test.go b/handlers/media_test.go index 3296b9505..d4ea4bea8 100644 --- a/handlers/media_test.go +++ b/handlers/media_test.go @@ -13,15 +13,15 @@ func TestResolveAttachments(t *testing.T) { ctx := context.Background() mb := courier.NewMockBackend() - imageJPG := courier.NewMockMedia("image/jpeg", "http://mock.com/1234/test.jpg", 1024*1024, 640, 480, 0, nil) + imageJPG := courier.NewMockMedia("test.jpg", "image/jpeg", "http://mock.com/1234/test.jpg", 1024*1024, 640, 480, 0, nil) - audioM4A := courier.NewMockMedia("audio/mp4", "http://mock.com/2345/test.m4a", 1024*1024, 0, 0, 200, nil) - audioMP3 := courier.NewMockMedia("audio/mp3", "http://mock.com/3456/test.mp3", 1024*1024, 0, 0, 200, []courier.Media{audioM4A}) + audioM4A := courier.NewMockMedia("test.m4a", "audio/mp4", "http://mock.com/2345/test.m4a", 1024*1024, 0, 0, 200, nil) + audioMP3 := courier.NewMockMedia("test.mp3", "audio/mp3", "http://mock.com/3456/test.mp3", 1024*1024, 0, 0, 200, []courier.Media{audioM4A}) - thumbJPG := courier.NewMockMedia("image/jpeg", "http://mock.com/4567/test.jpg", 1024*1024, 640, 480, 0, nil) - videoMP4 := courier.NewMockMedia("video/mp4", "http://mock.com/5678/test.mp4", 1024*1024, 0, 0, 1000, []courier.Media{thumbJPG}) + thumbJPG := courier.NewMockMedia("test.jpg", "image/jpeg", "http://mock.com/4567/test.jpg", 1024*1024, 640, 480, 0, nil) + videoMP4 := courier.NewMockMedia("test.mp4", "video/mp4", "http://mock.com/5678/test.mp4", 1024*1024, 0, 0, 1000, []courier.Media{thumbJPG}) - videoMOV := courier.NewMockMedia("video/quicktime", "http://mock.com/6789/test.mov", 100*1024*1024, 0, 0, 2000, nil) + videoMOV := courier.NewMockMedia("test.mov", "video/quicktime", "http://mock.com/6789/test.mov", 100*1024*1024, 0, 0, 2000, nil) mb.MockMedia(imageJPG) mb.MockMedia(audioMP3) @@ -36,11 +36,11 @@ func TestResolveAttachments(t *testing.T) { err string }{ { // 0: user entered image URL - attachments: []string{"image:https://example.com/image.jpg"}, + attachments: []string{"image:https://example.com/image%201.jpg"}, mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/png"}}}, // ignored allowURLOnly: true, resolved: []*handlers.Attachment{ - {Type: handlers.MediaTypeImage, ContentType: "image", URL: "https://example.com/image.jpg"}, + {Type: handlers.MediaTypeImage, Name: "image 1.jpg", ContentType: "image", URL: "https://example.com/image%201.jpg"}, }, }, { // 1: user entered image URL, URL only attachments not allowed @@ -54,7 +54,7 @@ func TestResolveAttachments(t *testing.T) { mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/jpeg", "image/png"}}}, allowURLOnly: true, resolved: []*handlers.Attachment{ - {Type: handlers.MediaTypeImage, ContentType: "image/jpeg", URL: "http://mock.com/1234/test.jpg", Media: imageJPG, Thumbnail: nil}, + {Type: handlers.MediaTypeImage, Name: "test.jpg", ContentType: "image/jpeg", URL: "http://mock.com/1234/test.jpg", Media: imageJPG, Thumbnail: nil}, }, }, { // 3: unresolveable uploaded image URL @@ -62,7 +62,7 @@ func TestResolveAttachments(t *testing.T) { mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/jpeg", "image/png"}}}, allowURLOnly: true, resolved: []*handlers.Attachment{ - {Type: handlers.MediaTypeImage, ContentType: "image/jpeg", URL: "http://mock.com/9876/gone.jpg", Media: nil, Thumbnail: nil}, + {Type: handlers.MediaTypeImage, Name: "gone.jpg", ContentType: "image/jpeg", URL: "http://mock.com/9876/gone.jpg", Media: nil, Thumbnail: nil}, }, }, { // 4: unresolveable uploaded image URL, URL only attachments not allowed @@ -82,7 +82,7 @@ func TestResolveAttachments(t *testing.T) { mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeAudio: {Types: []string{"audio/mp3", "audio/mp4"}}}, allowURLOnly: true, resolved: []*handlers.Attachment{ - {Type: handlers.MediaTypeAudio, ContentType: "audio/mp3", URL: "http://mock.com/3456/test.mp3", Media: audioMP3, Thumbnail: nil}, + {Type: handlers.MediaTypeAudio, Name: "test.mp3", ContentType: "audio/mp3", URL: "http://mock.com/3456/test.mp3", Media: audioMP3, Thumbnail: nil}, }, }, { // 7: resolveable uploaded audio URL, type not in supported types, but has alternate @@ -90,7 +90,7 @@ func TestResolveAttachments(t *testing.T) { mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeAudio: {Types: []string{"audio/mp4"}}}, allowURLOnly: true, resolved: []*handlers.Attachment{ - {Type: handlers.MediaTypeAudio, ContentType: "audio/mp4", URL: "http://mock.com/2345/test.m4a", Media: audioM4A, Thumbnail: nil}, + {Type: handlers.MediaTypeAudio, Name: "test.m4a", ContentType: "audio/mp4", URL: "http://mock.com/2345/test.m4a", Media: audioM4A, Thumbnail: nil}, }, }, { // 8: resolveable uploaded video URL, has thumbnail @@ -98,7 +98,7 @@ func TestResolveAttachments(t *testing.T) { mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeVideo: {Types: []string{"video/mp4", "video/quicktime"}}}, allowURLOnly: true, resolved: []*handlers.Attachment{ - {Type: handlers.MediaTypeVideo, ContentType: "video/mp4", URL: "http://mock.com/5678/test.mp4", Media: videoMP4, Thumbnail: thumbJPG}, + {Type: handlers.MediaTypeVideo, Name: "test.mp4", ContentType: "video/mp4", URL: "http://mock.com/5678/test.mp4", Media: videoMP4, Thumbnail: thumbJPG}, }, }, { // 9: resolveable uploaded video URL, no thumbnail @@ -106,7 +106,7 @@ func TestResolveAttachments(t *testing.T) { mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeVideo: {Types: []string{"video/mp4", "video/quicktime"}}}, allowURLOnly: true, resolved: []*handlers.Attachment{ - {Type: handlers.MediaTypeVideo, ContentType: "video/quicktime", URL: "http://mock.com/6789/test.mov", Media: videoMOV, Thumbnail: nil}, + {Type: handlers.MediaTypeVideo, Name: "test.mov", ContentType: "video/quicktime", URL: "http://mock.com/6789/test.mov", Media: videoMOV, Thumbnail: nil}, }, }, { // 10: resolveable uploaded video URL, too big diff --git a/test.go b/test.go index 95130e346..15f6cf555 100644 --- a/test.go +++ b/test.go @@ -758,6 +758,7 @@ func ReadFile(path string) []byte { //----------------------------------------------------------------------------- type mockMedia struct { + name string contentType string url string size int @@ -767,6 +768,7 @@ type mockMedia struct { alternates []Media } +func (m *mockMedia) Name() string { return m.name } func (m *mockMedia) ContentType() string { return m.contentType } func (m *mockMedia) URL() string { return m.url } func (m *mockMedia) Size() int { return m.size } @@ -775,8 +777,9 @@ func (m *mockMedia) Height() int { return m.height } func (m *mockMedia) Duration() int { return m.duration } func (m *mockMedia) Alternates() []Media { return m.alternates } -func NewMockMedia(contentType, url string, size, width, height, duration int, alternates []Media) Media { +func NewMockMedia(name, contentType, url string, size, width, height, duration int, alternates []Media) Media { return &mockMedia{ + name: name, contentType: contentType, url: url, size: size, From cff9e34ffba218b60a2afa2a7defa97451bedf1a Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 5 Aug 2022 10:58:29 -0500 Subject: [PATCH 047/294] Add test for NewChannelLogFromTrace --- channel_log_test.go | 53 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 channel_log_test.go diff --git a/channel_log_test.go b/channel_log_test.go new file mode 100644 index 000000000..1c85631d4 --- /dev/null +++ b/channel_log_test.go @@ -0,0 +1,53 @@ +package courier_test + +import ( + "net/http" + "testing" + + "github.com/nyaruka/courier" + "github.com/nyaruka/gocommon/httpx" + "github.com/stretchr/testify/assert" +) + +func TestNewChannelLogFromTrace(t *testing.T) { + httpx.SetRequestor(httpx.NewMockRequestor(map[string][]httpx.MockResponse{ + "https://api.messages.com/send.json": { + httpx.NewMockResponse(200, nil, []byte(`{"status":"success"}`)), + httpx.MockConnectionError, + }, + })) + defer httpx.SetRequestor(httpx.DefaultRequestor) + + channel := courier.NewMockChannel("fef91e9b-a6ed-44fb-b6ce-feed8af585a8", "NX", "1234", "US", nil) + + // make a request that will have a response + req, _ := http.NewRequest("POST", "https://api.messages.com/send.json", nil) + trace, err := httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) + assert.NoError(t, err) + + log := courier.NewChannelLogFromTrace("Send message", channel, courier.NewMsgID(1234), trace) + + assert.Equal(t, "Send message", log.Description) + assert.Equal(t, channel, log.Channel) + assert.Equal(t, courier.NewMsgID(1234), log.MsgID) + assert.Equal(t, "POST", log.Method) + assert.Equal(t, "https://api.messages.com/send.json", log.URL) + assert.Equal(t, 200, log.StatusCode) + assert.Equal(t, "", log.Error) + assert.Equal(t, "POST /send.json HTTP/1.1\r\nHost: api.messages.com\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 0\r\nAccept-Encoding: gzip\r\n\r\n", log.Request) + assert.Equal(t, "HTTP/1.0 200 OK\r\nContent-Length: 20\r\n\r\n{\"status\":\"success\"}", log.Response) + assert.Equal(t, trace.StartTime, log.CreatedOn) + assert.Equal(t, trace.EndTime.Sub(trace.StartTime), log.Elapsed) + + // make a request that has no response (connection error) + req, _ = http.NewRequest("POST", "https://api.messages.com/send.json", nil) + trace, err = httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) + assert.EqualError(t, err, "unable to connect to server") + + log = courier.NewChannelLogFromTrace("Send message", channel, courier.NewMsgID(1234), trace) + + assert.Equal(t, 0, log.StatusCode) + assert.Equal(t, "", log.Error) + assert.Equal(t, "POST /send.json HTTP/1.1\r\nHost: api.messages.com\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 0\r\nAccept-Encoding: gzip\r\n\r\n", log.Request) + assert.Equal(t, "", log.Response) +} From 7c98ac214fd4741a8e488042763c6fbe4fecf60e Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 5 Aug 2022 15:44:15 -0500 Subject: [PATCH 048/294] Use httpx.DoTrace for some more channels --- handlers/burstsms/burstsms.go | 8 +++----- handlers/chikka/chikka.go | 14 ++++++-------- handlers/clickatell/clickatell.go | 6 +++--- handlers/clickmobile/clickmobile.go | 9 ++++----- handlers/clicksend/clicksend.go | 9 ++++----- handlers/dart/dart.go | 7 +++---- handlers/discord/discord.go | 5 ++--- handlers/dmark/dmark.go | 7 +++---- handlers/globe/globe.go | 5 ++--- handlers/hormuud/hormuud.go | 30 ++++++++++++++--------------- handlers/i2sms/i2sms.go | 9 +++------ handlers/junebug/junebug.go | 7 +++---- handlers/kaleyra/kaleyra.go | 18 ++++++++--------- handlers/shaqodoon/shaqodoon.go | 5 ++--- handlers/yo/yo.go | 8 +++----- handlers/zenvia/zenvia.go | 7 +++---- handlers/zenviaold/zenviaold.go | 7 +++---- 17 files changed, 71 insertions(+), 90 deletions(-) diff --git a/handlers/burstsms/burstsms.go b/handlers/burstsms/burstsms.go index 627a9d50c..96c9ea460 100644 --- a/handlers/burstsms/burstsms.go +++ b/handlers/burstsms/burstsms.go @@ -10,7 +10,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" ) var ( @@ -77,7 +76,6 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus } req, err := http.NewRequest(http.MethodPost, sendURL, strings.NewReader(form.Encode())) - if err != nil { return nil, err } @@ -85,10 +83,10 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil @@ -96,7 +94,7 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus // parse our response as json response := &mtResponse{} - err = json.Unmarshal(rr.Body, response) + err = json.Unmarshal(trace.ResponseBody, response) if err != nil { log.WithError("Message Send Error", err) break diff --git a/handlers/chikka/chikka.go b/handlers/chikka/chikka.go index d1b88f0ea..6d94b6c8d 100644 --- a/handlers/chikka/chikka.go +++ b/handlers/chikka/chikka.go @@ -12,7 +12,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" ) var ( @@ -141,11 +140,11 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) - if rr.StatusCode == 400 { - message, _ := jsonparser.GetString([]byte(rr.Body), "message") - description, _ := jsonparser.GetString([]byte(rr.Body), "description") + if trace.Response != nil && trace.Response.StatusCode == 400 { + message, _ := jsonparser.GetString(trace.ResponseBody, "message") + description, _ := jsonparser.GetString(trace.ResponseBody, "description") if message == "BAD REQUEST" && description == `Invalid\/Used Request ID` { delete(form, "request_id") @@ -153,14 +152,13 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req, _ = http.NewRequest(http.MethodPost, sendURL, strings.NewReader(form.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - rr, err = utils.MakeHTTPRequest(req) + trace, err = handlers.MakeHTTPRequest(req) } - } // record our status and log - status.AddLog(courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err)) + status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) if err != nil { return status, nil } diff --git a/handlers/clickatell/clickatell.go b/handlers/clickatell/clickatell.go index 351e1624f..171618cac 100644 --- a/handlers/clickatell/clickatell.go +++ b/handlers/clickatell/clickatell.go @@ -195,17 +195,17 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Send Error", err) status.AddLog(log) if err != nil { return status, nil } // try to read out our message id, if we can't then this was a failure - externalID, err := jsonparser.GetString(rr.Body, "messages", "[0]", "apiMessageId") + externalID, err := jsonparser.GetString(trace.ResponseBody, "messages", "[0]", "apiMessageId") if err != nil { log.WithError("Send Error", err) } else { diff --git a/handlers/clickmobile/clickmobile.go b/handlers/clickmobile/clickmobile.go index 6103127c5..57fbfd571 100644 --- a/handlers/clickmobile/clickmobile.go +++ b/handlers/clickmobile/clickmobile.go @@ -13,7 +13,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/dates" ) @@ -157,19 +156,19 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } - responseCode, err := jsonparser.GetString(rr.Body, "code") + responseCode, err := jsonparser.GetString(trace.ResponseBody, "code") if responseCode == "000" { status.SetStatus(courier.MsgWired) } else { - log.WithError("Message Send Error", fmt.Errorf("Received invalid response content: %s", string(rr.Body))) + log.WithError("Message Send Error", fmt.Errorf("Received invalid response content: %s", string(trace.ResponseBody))) } } return status, nil diff --git a/handlers/clicksend/clicksend.go b/handlers/clicksend/clicksend.go index 3c10a8fb6..cdfeadd10 100644 --- a/handlers/clicksend/clicksend.go +++ b/handlers/clicksend/clicksend.go @@ -10,7 +10,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/pkg/errors" ) @@ -94,22 +93,22 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.SetBasicAuth(username, password) - rr, err := utils.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + trace, err := handlers.MakeHTTPRequest(req) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } // first read our status - s, err := jsonparser.GetString(rr.Body, "data", "messages", "[0]", "status") + s, err := jsonparser.GetString(trace.ResponseBody, "data", "messages", "[0]", "status") if s != "SUCCESS" { log.WithError("Message Send Error", errors.Errorf("received non SUCCESS status: %s", s)) return status, nil } // then get our external id - id, err := jsonparser.GetString(rr.Body, "data", "messages", "[0]", "message_id") + id, err := jsonparser.GetString(trace.ResponseBody, "data", "messages", "[0]", "message_id") if err != nil { log.WithError("Message Send Error", errors.Errorf("unable to get message_id for message")) return status, nil diff --git a/handlers/dart/dart.go b/handlers/dart/dart.go index 70e4a4f00..29b76a3b0 100644 --- a/handlers/dart/dart.go +++ b/handlers/dart/dart.go @@ -14,7 +14,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" ) @@ -180,16 +179,16 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Send Error", err) status.AddLog(log) if err != nil { return status, nil } - responseText := fmt.Sprintf("%s", rr.Body) + responseText := string(trace.ResponseBody) if responseText != "000" { errorMessage := "Unknown error" if responseText == "001" { diff --git a/handlers/discord/discord.go b/handlers/discord/discord.go index 999f4ce6d..bb60f9d00 100644 --- a/handlers/discord/discord.go +++ b/handlers/discord/discord.go @@ -14,7 +14,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" "github.com/pkg/errors" ) @@ -209,10 +208,10 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Authorization", authorization) } - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil diff --git a/handlers/dmark/dmark.go b/handlers/dmark/dmark.go index d6551bef1..2244d4bd4 100644 --- a/handlers/dmark/dmark.go +++ b/handlers/dmark/dmark.go @@ -11,7 +11,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/pkg/errors" ) @@ -136,17 +135,17 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Token %s", auth)) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } // grab the external id - externalID, err := jsonparser.GetString([]byte(rr.Body), "sms_id") + externalID, err := jsonparser.GetString(trace.ResponseBody, "sms_id") if err != nil { log.WithError("Message Send Error", errors.Errorf("unable to get sms_id from body")) return status, nil diff --git a/handlers/globe/globe.go b/handlers/globe/globe.go index 093df05f0..36b7ee84d 100644 --- a/handlers/globe/globe.go +++ b/handlers/globe/globe.go @@ -11,7 +11,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" ) var ( @@ -164,8 +163,8 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + trace, err := handlers.MakeHTTPRequest(req) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil diff --git a/handlers/hormuud/hormuud.go b/handlers/hormuud/hormuud.go index b890dd7e4..67948cf64 100644 --- a/handlers/hormuud/hormuud.go +++ b/handlers/hormuud/hormuud.go @@ -14,7 +14,7 @@ import ( "github.com/gomodule/redigo/redis" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" + "github.com/nyaruka/gocommon/httpx" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -84,14 +84,14 @@ type mtPayload struct { func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - token, rr, err := h.FetchToken(ctx, msg.Channel(), msg) - if rr == nil && err != nil { + token, trace, err := h.FetchToken(ctx, msg.Channel(), msg) + if trace == nil && err != nil { return nil, errors.Wrapf(err, "unable to fetch token") } // if we made a request for our token, stash that in our status - if rr != nil { - log := courier.NewChannelLogFromRR("Token Retrieved", msg.Channel(), msg.ID(), rr).WithError("Token Retrieval Error", err) + if trace != nil { + log := courier.NewChannelLogFromTrace("Token Retrieved", msg.Channel(), msg.ID(), trace).WithError("Token Retrieval Error", err) status.AddLog(log) } @@ -123,8 +123,8 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) - rr, err := utils.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + trace, err := handlers.MakeHTTPRequest(req) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil @@ -132,7 +132,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat status.SetStatus(courier.MsgWired) // try to get the message id out - id, _ := jsonparser.GetString(rr.Body, "Data", "MessageID") + id, _ := jsonparser.GetString(trace.ResponseBody, "Data", "MessageID") if id != "" && i == 0 { status.SetExternalID(id) } @@ -146,7 +146,7 @@ type tokenResponse struct { } // FetchToken gets the current token for this channel, either from Redis if cached or by requesting it -func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg courier.Msg) (string, *utils.RequestResponse, error) { +func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg courier.Msg) (string, *httpx.Trace, error) { // first check whether we have it in redis conn := h.Backend().RedisPool().Get() token, err := redis.String(conn.Do("GET", fmt.Sprintf("hm_token_%s", channel.UUID()))) @@ -179,18 +179,18 @@ func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg c req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) if err != nil { - return "", rr, errors.Wrapf(err, "error making token request") + return "", trace, errors.Wrapf(err, "error making token request") } - token, err = jsonparser.GetString(rr.Body, "access_token") + token, err = jsonparser.GetString(trace.ResponseBody, "access_token") if err != nil { - return "", rr, errors.Wrapf(err, "error getting access_token from response") + return "", trace, errors.Wrapf(err, "error getting access_token from response") } if token == "" { - return "", rr, errors.Errorf("no access token returned") + return "", trace, errors.Errorf("no access token returned") } // we got a token, cache it to redis with a 90 minute expiration @@ -202,5 +202,5 @@ func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg c logrus.WithError(err).Error("error caching HM access token") } - return token, rr, nil + return token, trace, nil } diff --git a/handlers/i2sms/i2sms.go b/handlers/i2sms/i2sms.go index ff16df532..51474bb5e 100644 --- a/handlers/i2sms/i2sms.go +++ b/handlers/i2sms/i2sms.go @@ -11,7 +11,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" ) const ( @@ -117,10 +116,10 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil @@ -128,15 +127,13 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus // parse our response as JSON response := &mtResponse{} - err = json.Unmarshal(rr.Body, response) + err = json.Unmarshal(trace.ResponseBody, response) if err != nil { log.WithError("Message Send Error", err) break } // we always get 00 on success - fmt.Println(string(rr.Body)) - fmt.Printf("%++v\n", response) if response.ErrorCode == "00" { status.SetStatus(courier.MsgWired) status.SetExternalID(response.Result.SessionID) diff --git a/handlers/junebug/junebug.go b/handlers/junebug/junebug.go index d2c3c978d..eaf532066 100644 --- a/handlers/junebug/junebug.go +++ b/handlers/junebug/junebug.go @@ -11,7 +11,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/pkg/errors" ) @@ -198,16 +197,16 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.SetBasicAuth(username, password) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } - externalID, err := jsonparser.GetString(rr.Body, "result", "message_id") + externalID, err := jsonparser.GetString(trace.ResponseBody, "result", "message_id") if err != nil { log.WithError("Message Send Error", errors.Errorf("unable to get result.message_id from body")) return status, nil diff --git a/handlers/kaleyra/kaleyra.go b/handlers/kaleyra/kaleyra.go index 850d98751..d12815281 100644 --- a/handlers/kaleyra/kaleyra.go +++ b/handlers/kaleyra/kaleyra.go @@ -16,7 +16,7 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" + "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/urns" "github.com/pkg/errors" ) @@ -151,7 +151,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat sendURL := fmt.Sprintf("%s/v1/%s/messages", baseURL, accountSID) var logs []*courier.ChannelLog - var kwaRes *utils.RequestResponse + var kwaRes *httpx.Trace var kwaErr error // make multipart form requests if we have attachments, the kaleyra api doesn't supports media url nor media upload before send @@ -162,9 +162,9 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat // download media req, _ := http.NewRequest(http.MethodGet, attachmentURL, nil) - res, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) if err != nil { - log := courier.NewChannelLogFromRR("Media Fetch", msg.Channel(), msg.ID(), res) + log := courier.NewChannelLogFromTrace("Media Fetch", msg.Channel(), msg.ID(), trace) logs = append(logs, log) kwaErr = err break @@ -176,7 +176,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat body := &bytes.Buffer{} writer := multipart.NewWriter(body) part, err := writer.CreateFormFile("media", fileName) - _, err = io.Copy(part, bytes.NewReader(res.Body)) + _, err = io.Copy(part, bytes.NewReader(trace.ResponseBody)) if err != nil { elapsed := time.Now().Sub(start) log := courier.NewChannelLogFromError("Media Send APPEND media Field Error", msg.Channel(), msg.ID(), elapsed, err) @@ -215,7 +215,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat // send multipart form req, _ = http.NewRequest(http.MethodPost, sendURL, body) req.Header.Set("Content-Type", writer.FormDataContentType()) - kwaRes, kwaErr = utils.MakeHTTPRequest(req) + kwaRes, kwaErr = handlers.MakeHTTPRequest(req) } } else { form := url.Values{} @@ -231,11 +231,11 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req, _ := http.NewRequest(http.MethodPost, sendURL, strings.NewReader(form.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - kwaRes, kwaErr = utils.MakeHTTPRequest(req) + kwaRes, kwaErr = handlers.MakeHTTPRequest(req) } if kwaRes != nil { - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), kwaRes).WithError("Message Send Error", kwaErr) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), kwaRes).WithError("Message Send Error", kwaErr) logs = append(logs, log) } // add logs to status @@ -249,7 +249,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } // record external id from the last sent msg request - externalID, err := jsonparser.GetString(kwaRes.Body, "id") + externalID, err := jsonparser.GetString(kwaRes.ResponseBody, "id") if err == nil { status.SetExternalID(externalID) } diff --git a/handlers/shaqodoon/shaqodoon.go b/handlers/shaqodoon/shaqodoon.go index 8ecc386d2..4aaad63a7 100644 --- a/handlers/shaqodoon/shaqodoon.go +++ b/handlers/shaqodoon/shaqodoon.go @@ -10,7 +10,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/pkg/errors" ) @@ -115,10 +114,10 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - rr, err := utils.MakeInsecureHTTPRequest(req) + trace, err := handlers.MakeInsecureHTTPRequest(req) status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - status.AddLog(courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err)) + status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) if err == nil { status.SetStatus(courier.MsgWired) } diff --git a/handlers/yo/yo.go b/handlers/yo/yo.go index c411218e9..de1292f1e 100644 --- a/handlers/yo/yo.go +++ b/handlers/yo/yo.go @@ -14,7 +14,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/pkg/errors" ) @@ -126,21 +125,20 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat sendURL.RawQuery = form.Encode() req, err := http.NewRequest(http.MethodGet, sendURL.String(), nil) - if err != nil { return nil, err } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - rr, err := utils.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + trace, err := handlers.MakeHTTPRequest(req) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { continue } - responseQS, _ := url.ParseQuery(string(rr.Body)) + responseQS, _ := url.ParseQuery(string(trace.ResponseBody)) // check whether we were blacklisted createMessage, _ := responseQS["ybs_autocreate_message"] diff --git a/handlers/zenvia/zenvia.go b/handlers/zenvia/zenvia.go index b4c776344..a234d0f13 100644 --- a/handlers/zenvia/zenvia.go +++ b/handlers/zenvia/zenvia.go @@ -12,7 +12,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" "github.com/pkg/errors" ) @@ -260,16 +259,16 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.Header.Set("X-API-TOKEN", token) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } - externalID, err := jsonparser.GetString(rr.Body, "id") + externalID, err := jsonparser.GetString(trace.ResponseBody, "id") if err != nil { log.WithError("Message Send Error", errors.Errorf("unable to get id from body")) return status, nil diff --git a/handlers/zenviaold/zenviaold.go b/handlers/zenviaold/zenviaold.go index 95109f40f..a95338f7a 100644 --- a/handlers/zenviaold/zenviaold.go +++ b/handlers/zenviaold/zenviaold.go @@ -12,7 +12,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/pkg/errors" ) @@ -196,17 +195,17 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.SetBasicAuth(username, password) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } // was this request successful? - responseMsgStatus, _ := jsonparser.GetString(rr.Body, "sendSmsResponse", "statusCode") + responseMsgStatus, _ := jsonparser.GetString(trace.ResponseBody, "sendSmsResponse", "statusCode") msgStatus, found := statusMapping[responseMsgStatus] if msgStatus == courier.MsgErrored || !found { log.WithError("Message Send Error", errors.Errorf("received non-success response from Zenvia '%s'", responseMsgStatus)) From 6df69ad2d6353b3dbf9585f785c5b3a4ac38b4e6 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 8 Aug 2022 11:18:35 -0500 Subject: [PATCH 049/294] Fix URLs from non-resolved attachments --- handlers/media.go | 6 ++++++ handlers/media_test.go | 32 ++++++++++++++++++++------------ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/handlers/media.go b/handlers/media.go index 73f183418..2340ea0d4 100644 --- a/handlers/media.go +++ b/handlers/media.go @@ -67,6 +67,12 @@ func resolveAttachment(ctx context.Context, b courier.Backend, attachment string if media == nil { // if the channel type allows it, we can still use the media URL without being able to resolve it if allowURLOnly { + // potentially fix the URL which might not be properly encoded + parsedURL, err := url.Parse(mediaUrl) + if err == nil { + mediaUrl = parsedURL.String() + } + mediaType, _ := parseContentType(contentType) name := filenameFromURL(mediaUrl) return &Attachment{Type: mediaType, Name: name, ContentType: contentType, URL: mediaUrl}, nil diff --git a/handlers/media_test.go b/handlers/media_test.go index d4ea4bea8..a6d5b2b9a 100644 --- a/handlers/media_test.go +++ b/handlers/media_test.go @@ -43,13 +43,21 @@ func TestResolveAttachments(t *testing.T) { {Type: handlers.MediaTypeImage, Name: "image 1.jpg", ContentType: "image", URL: "https://example.com/image%201.jpg"}, }, }, - { // 1: user entered image URL, URL only attachments not allowed + { // 1: user entered audio URL which isn't properly escaped + attachments: []string{"image:https://example.com/audio 1.m4a"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"audio/mp3"}}}, // ignored + allowURLOnly: true, + resolved: []*handlers.Attachment{ + {Type: handlers.MediaTypeImage, Name: "audio 1.m4a", ContentType: "image", URL: "https://example.com/audio%201.m4a"}, + }, + }, + { // 2: user entered image URL, URL only attachments not allowed attachments: []string{"image:https://example.com/image.jpg"}, mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/png"}}}, // ignored allowURLOnly: false, resolved: []*handlers.Attachment{}, }, - { // 2: resolveable uploaded image URL + { // 3: resolveable uploaded image URL attachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/jpeg", "image/png"}}}, allowURLOnly: true, @@ -57,7 +65,7 @@ func TestResolveAttachments(t *testing.T) { {Type: handlers.MediaTypeImage, Name: "test.jpg", ContentType: "image/jpeg", URL: "http://mock.com/1234/test.jpg", Media: imageJPG, Thumbnail: nil}, }, }, - { // 3: unresolveable uploaded image URL + { // 4: unresolveable uploaded image URL attachments: []string{"image/jpeg:http://mock.com/9876/gone.jpg"}, mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/jpeg", "image/png"}}}, allowURLOnly: true, @@ -65,19 +73,19 @@ func TestResolveAttachments(t *testing.T) { {Type: handlers.MediaTypeImage, Name: "gone.jpg", ContentType: "image/jpeg", URL: "http://mock.com/9876/gone.jpg", Media: nil, Thumbnail: nil}, }, }, - { // 4: unresolveable uploaded image URL, URL only attachments not allowed + { // 5: unresolveable uploaded image URL, URL only attachments not allowed attachments: []string{"image/jpeg:http://mock.com/9876/gone.jpg"}, mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/jpeg", "image/png"}}}, allowURLOnly: false, resolved: []*handlers.Attachment{}, }, - { // 5: resolveable uploaded image URL, type not in supported types + { // 6: resolveable uploaded image URL, type not in supported types attachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/png"}}}, allowURLOnly: true, resolved: []*handlers.Attachment{}, }, - { // 6: resolveable uploaded audio URL, type in supported types + { // 7: resolveable uploaded audio URL, type in supported types attachments: []string{"audio/mp3:http://mock.com/3456/test.mp3"}, mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeAudio: {Types: []string{"audio/mp3", "audio/mp4"}}}, allowURLOnly: true, @@ -85,7 +93,7 @@ func TestResolveAttachments(t *testing.T) { {Type: handlers.MediaTypeAudio, Name: "test.mp3", ContentType: "audio/mp3", URL: "http://mock.com/3456/test.mp3", Media: audioMP3, Thumbnail: nil}, }, }, - { // 7: resolveable uploaded audio URL, type not in supported types, but has alternate + { // 8: resolveable uploaded audio URL, type not in supported types, but has alternate attachments: []string{"audio/mp3:http://mock.com/3456/test.mp3"}, mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeAudio: {Types: []string{"audio/mp4"}}}, allowURLOnly: true, @@ -93,7 +101,7 @@ func TestResolveAttachments(t *testing.T) { {Type: handlers.MediaTypeAudio, Name: "test.m4a", ContentType: "audio/mp4", URL: "http://mock.com/2345/test.m4a", Media: audioM4A, Thumbnail: nil}, }, }, - { // 8: resolveable uploaded video URL, has thumbnail + { // 9: resolveable uploaded video URL, has thumbnail attachments: []string{"video/mp4:http://mock.com/5678/test.mp4"}, mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeVideo: {Types: []string{"video/mp4", "video/quicktime"}}}, allowURLOnly: true, @@ -101,7 +109,7 @@ func TestResolveAttachments(t *testing.T) { {Type: handlers.MediaTypeVideo, Name: "test.mp4", ContentType: "video/mp4", URL: "http://mock.com/5678/test.mp4", Media: videoMP4, Thumbnail: thumbJPG}, }, }, - { // 9: resolveable uploaded video URL, no thumbnail + { // 10: resolveable uploaded video URL, no thumbnail attachments: []string{"video/quicktime:http://mock.com/6789/test.mov"}, mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeVideo: {Types: []string{"video/mp4", "video/quicktime"}}}, allowURLOnly: true, @@ -109,18 +117,18 @@ func TestResolveAttachments(t *testing.T) { {Type: handlers.MediaTypeVideo, Name: "test.mov", ContentType: "video/quicktime", URL: "http://mock.com/6789/test.mov", Media: videoMOV, Thumbnail: nil}, }, }, - { // 10: resolveable uploaded video URL, too big + { // 11: resolveable uploaded video URL, too big attachments: []string{"video/quicktime:http://mock.com/6789/test.mov"}, mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeVideo: {Types: []string{"video/quicktime"}, MaxBytes: 10 * 1024 * 1024}}, allowURLOnly: true, resolved: []*handlers.Attachment{}, }, - { // 11: invalid attachment format + { // 12: invalid attachment format attachments: []string{"image"}, mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{}, err: "invalid attachment format: image", }, - { // 12: invalid attachment format (missing content type) + { // 13: invalid attachment format (missing content type) attachments: []string{"http://mock.com/1234/test.jpg"}, mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{}, err: "invalid attachment format: http://mock.com/1234/test.jpg", From 0186fa012687cf3334e831066b7eea7bb428f574 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 8 Aug 2022 13:01:53 -0500 Subject: [PATCH 050/294] Update CHANGELOG.md for v7.5.6 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8707df10b..c8441b6c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +v7.5.6 +---------- + * Fix URLs from non-resolved attachments that may not be properly escaped + * Use httpx.DoTrace for some channels + * Convert telegram handler to use ResolveAttachments + * Add support for resolving media on the backend + v7.5.5 ---------- * Switch to using null.Map instead of utils.NullMap From 966c780e742b76d0c62ab119bbbfb94f7b0c00ab Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 8 Aug 2022 13:14:36 -0500 Subject: [PATCH 051/294] Convert remaining channel types to use httpx.Trace --- channel_log.go | 19 --- handlers/external/external.go | 9 +- handlers/facebook/facebook.go | 26 ++-- handlers/facebookapp/facebookapp.go | 33 ++--- handlers/firebase/firebase.go | 9 +- handlers/freshchat/freshchat.go | 5 +- handlers/highconnection/highconnection.go | 4 +- handlers/infobip/infobip.go | 9 +- handlers/jasmin/jasmin.go | 10 +- handlers/jiochat/jiochat.go | 16 +-- handlers/kannel/kannel.go | 12 +- handlers/line/line.go | 14 +-- handlers/m3tech/m3tech.go | 6 +- handlers/macrokiosk/macrokiosk.go | 7 +- handlers/mblox/mblox.go | 7 +- handlers/messangi/messangi.go | 8 +- handlers/mtarget/mtarget.go | 9 +- handlers/nexmo/nexmo.go | 14 +-- handlers/novo/novo.go | 7 +- handlers/playmobile/playmobile.go | 7 +- handlers/plivo/plivo.go | 7 +- handlers/redrabbit/redrabbit.go | 7 +- handlers/rocketchat/rocketchat.go | 10 +- handlers/slack/slack.go | 34 +++--- handlers/smscentral/smscentral.go | 9 +- handlers/start/start.go | 8 +- handlers/telesom/telesom.go | 9 +- handlers/thinq/thinq.go | 14 +-- handlers/twiml/twiml.go | 10 +- handlers/twitter/twitter.go | 40 ++++--- handlers/viber/viber.go | 49 +++++--- handlers/vk/vk.go | 40 ++++--- handlers/wavy/wavy.go | 7 +- handlers/wechat/wechat.go | 18 +-- handlers/whatsapp/whatsapp.go | 58 ++++----- server_test.go | 28 ++--- utils/http.go | 140 ---------------------- 37 files changed, 286 insertions(+), 433 deletions(-) diff --git a/channel_log.go b/channel_log.go index 654e4dedb..d29d977f0 100644 --- a/channel_log.go +++ b/channel_log.go @@ -5,7 +5,6 @@ import ( "strings" "time" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/httpx" ) @@ -52,24 +51,6 @@ func sanitizeBody(body string) string { return body } -// NewChannelLogFromRR creates a new channel log for the passed in channel, id, and request/response log -func NewChannelLogFromRR(description string, channel Channel, msgID MsgID, rr *utils.RequestResponse) *ChannelLog { - log := &ChannelLog{ - Description: description, - Channel: channel, - MsgID: msgID, - Method: rr.Method, - URL: rr.URL, - StatusCode: rr.StatusCode, - Request: sanitizeBody(rr.Request), - Response: sanitizeBody(rr.Response), - CreatedOn: time.Now(), - Elapsed: rr.Elapsed, - } - - return log -} - // NewChannelLogFromTrace creates a new channel log for the passed in channel, id, and http trace func NewChannelLogFromTrace(description string, channel Channel, msgID MsgID, trace *httpx.Trace) *ChannelLog { log := &ChannelLog{ diff --git a/handlers/external/external.go b/handlers/external/external.go index da01ecce2..e118ca7a5 100644 --- a/handlers/external/external.go +++ b/handlers/external/external.go @@ -15,7 +15,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/gsm7" "github.com/nyaruka/gocommon/urns" @@ -364,19 +363,19 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set(hKey, fmt.Sprint(hValue)) } - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } - if responseContent == "" || strings.Contains(string(rr.Body), responseContent) { + if responseContent == "" || strings.Contains(string(trace.ResponseBody), responseContent) { status.SetStatus(courier.MsgWired) } else { - log.WithError("Message Send Error", fmt.Errorf("Received invalid response content: %s", string(rr.Body))) + log.WithError("Message Send Error", fmt.Errorf("Received invalid response content: %s", string(trace.ResponseBody))) } } diff --git a/handlers/facebook/facebook.go b/handlers/facebook/facebook.go index 75aff3de4..44c33d02c 100644 --- a/handlers/facebook/facebook.go +++ b/handlers/facebook/facebook.go @@ -107,12 +107,13 @@ func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w form.Set("access_token", authToken) req, _ := http.NewRequest(http.MethodPost, subscribeURL, strings.NewReader(form.Encode())) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - rr, err := utils.MakeHTTPRequest(req) + + trace, err := handlers.MakeHTTPRequest(req) // log if we get any kind of error - success, _ := jsonparser.GetBoolean([]byte(rr.Body), "success") + success, _ := jsonparser.GetBoolean(trace.ResponseBody, "success") if err != nil || !success { - logrus.WithField("channel_uuid", channel.UUID()).WithField("response", rr.Response).Error("error subscribing to Facebook page events") + logrus.WithField("channel_uuid", channel.UUID()).Error("error subscribing to Facebook page events") } }() @@ -545,23 +546,23 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } req, err := http.NewRequest(http.MethodPost, msgURL.String(), bytes.NewReader(jsonBody)) - if err != nil { return nil, err } + req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } - externalID, err := jsonparser.GetString(rr.Body, "message_id") + externalID, err := jsonparser.GetString(trace.ResponseBody, "message_id") if err != nil { log.WithError("Message Send Error", errors.Errorf("unable to get message_id from body")) return status, nil @@ -571,7 +572,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat if i == 0 { status.SetExternalID(externalID) if msg.URN().IsFacebookRef() { - recipientID, err := jsonparser.GetString(rr.Body, "recipient_id") + recipientID, err := jsonparser.GetString(trace.ResponseBody, "recipient_id") if err != nil { log.WithError("Message Send Error", errors.Errorf("unable to get recipient_id from body")) return status, nil @@ -639,14 +640,15 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn query.Set("access_token", accessToken) u.RawQuery = query.Encode() req, _ := http.NewRequest(http.MethodGet, u.String(), nil) - rr, err := utils.MakeHTTPRequest(req) + + trace, err := handlers.MakeHTTPRequest(req) if err != nil { - return nil, fmt.Errorf("unable to look up contact data:%s\n%s", err, rr.Response) + return nil, fmt.Errorf("unable to look up contact data: %s", err) } // read our first and last name - firstName, _ := jsonparser.GetString(rr.Body, "first_name") - lastName, _ := jsonparser.GetString(rr.Body, "last_name") + firstName, _ := jsonparser.GetString(trace.ResponseBody, "first_name") + lastName, _ := jsonparser.GetString(trace.ResponseBody, "last_name") return map[string]string{"name": utils.JoinNonEmpty(" ", firstName, lastName)}, nil } diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 3d5b65f5d..ceec98826 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -337,19 +337,19 @@ func resolveMediaURL(mediaID string, token string) (string, error) { base, _ := url.Parse(graphURL) path, _ := url.Parse(fmt.Sprintf("/%s", mediaID)) - retreiveURL := base.ResolveReference(path) + retrieveURL := base.ResolveReference(path) // set the access token as the authorization header - req, _ := http.NewRequest(http.MethodGet, retreiveURL.String(), nil) + req, _ := http.NewRequest(http.MethodGet, retrieveURL.String(), nil) //req.Header.Set("User-Agent", utils.HTTPUserAgent) req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) - resp, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) if err != nil { return "", err } - mediaURL, err := jsonparser.GetString(resp.Body, "url") + mediaURL, err := jsonparser.GetString(trace.ResponseBody, "url") return mediaURL, err } @@ -894,16 +894,16 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg) req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } - externalID, err := jsonparser.GetString(rr.Body, "message_id") + externalID, err := jsonparser.GetString(trace.ResponseBody, "message_id") if err != nil { log.WithError("Message Send Error", errors.Errorf("unable to get message_id from body")) return status, nil @@ -913,7 +913,7 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg) if i == 0 { status.SetExternalID(externalID) if msg.URN().IsFacebookRef() { - recipientID, err := jsonparser.GetString(rr.Body, "recipient_id") + recipientID, err := jsonparser.GetString(trace.ResponseBody, "recipient_id") if err != nil { log.WithError("Message Send Error", errors.Errorf("unable to get recipient_id from body")) return status, nil @@ -1278,17 +1278,17 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg) req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } respPayload := &wacMTResponse{} - err = json.Unmarshal(rr.Body, respPayload) + err = json.Unmarshal(trace.ResponseBody, respPayload) if err != nil { log.WithError("Message Send Error", errors.Errorf("unable to unmarshal response body")) return status, nil @@ -1335,18 +1335,19 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn query.Set("access_token", accessToken) u.RawQuery = query.Encode() req, _ := http.NewRequest(http.MethodGet, u.String(), nil) - rr, err := utils.MakeHTTPRequest(req) + + trace, err := handlers.MakeHTTPRequest(req) if err != nil { - return nil, fmt.Errorf("unable to look up contact data:%s\n%s", err, rr.Response) + return nil, fmt.Errorf("unable to look up contact data: %s", err) } // read our first and last name or complete name if fmt.Sprint(channel.ChannelType()) == "FBA" { - firstName, _ := jsonparser.GetString(rr.Body, "first_name") - lastName, _ := jsonparser.GetString(rr.Body, "last_name") + firstName, _ := jsonparser.GetString(trace.ResponseBody, "first_name") + lastName, _ := jsonparser.GetString(trace.ResponseBody, "last_name") name = utils.JoinNonEmpty(" ", firstName, lastName) } else { - name, _ = jsonparser.GetString(rr.Body, "name") + name, _ = jsonparser.GetString(trace.ResponseBody, "name") } return map[string]string{"name": name}, nil diff --git a/handlers/firebase/firebase.go b/handlers/firebase/firebase.go index 5e9d414e8..421549d92 100644 --- a/handlers/firebase/firebase.go +++ b/handlers/firebase/firebase.go @@ -11,7 +11,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" "github.com/pkg/errors" ) @@ -195,15 +194,15 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("key=%s", fcmKey)) - rr, err := utils.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + trace, err := handlers.MakeHTTPRequest(req) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } // was this successful - success, _ := jsonparser.GetInt(rr.Body, "success") + success, _ := jsonparser.GetInt(trace.ResponseBody, "success") if success != 1 { log.WithError("Message Send Error", errors.Errorf("received non-1 value for success in response")) return status, nil @@ -211,7 +210,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat // grab the id if this is our first part if i == 0 { - externalID, err := jsonparser.GetInt(rr.Body, "multicast_id") + externalID, err := jsonparser.GetInt(trace.ResponseBody, "multicast_id") if err != nil { log.WithError("Message Send Error", errors.Errorf("unable to get multicast_id from response")) return status, nil diff --git a/handlers/freshchat/freshchat.go b/handlers/freshchat/freshchat.go index adf01ed38..86b26e55a 100644 --- a/handlers/freshchat/freshchat.go +++ b/handlers/freshchat/freshchat.go @@ -21,7 +21,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" ) @@ -169,10 +168,10 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat var bearer = "Bearer " + authToken req.Header.Set("Authorization", bearer) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, err diff --git a/handlers/highconnection/highconnection.go b/handlers/highconnection/highconnection.go index 70f2cec7c..ba76ec5ec 100644 --- a/handlers/highconnection/highconnection.go +++ b/handlers/highconnection/highconnection.go @@ -155,10 +155,10 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat if err != nil { return nil, err } - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil diff --git a/handlers/infobip/infobip.go b/handlers/infobip/infobip.go index 22acc4821..e165383bb 100644 --- a/handlers/infobip/infobip.go +++ b/handlers/infobip/infobip.go @@ -12,7 +12,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/pkg/errors" ) @@ -226,24 +225,24 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.SetBasicAuth(username, password) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace) status.AddLog(log) if err != nil { log.WithError("Message Send Error", err) return status, nil } - groupID, err := jsonparser.GetInt(rr.Body, "messages", "[0]", "status", "groupId") + groupID, err := jsonparser.GetInt(trace.ResponseBody, "messages", "[0]", "status", "groupId") if err != nil || (groupID != 1 && groupID != 3) { log.WithError("Message Send Error", errors.Errorf("received error status: '%d'", groupID)) return status, nil } - externalID, err := jsonparser.GetString(rr.Body, "messages", "[0]", "messageId") + externalID, err := jsonparser.GetString(trace.ResponseBody, "messages", "[0]", "messageId") if externalID != "" { status.SetExternalID(externalID) } diff --git a/handlers/jasmin/jasmin.go b/handlers/jasmin/jasmin.go index 91c33478d..b0e6ad163 100644 --- a/handlers/jasmin/jasmin.go +++ b/handlers/jasmin/jasmin.go @@ -11,7 +11,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/gsm7" ) @@ -160,19 +159,20 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat if err != nil { return nil, err } - rr, err := utils.MakeHTTPRequest(req) + + trace, err := handlers.MakeHTTPRequest(req) // record our status and log status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - status.AddLog(courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err)) + status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) if err == nil { status.SetStatus(courier.MsgWired) } // try to read our external id out - matches := idRegex.FindStringSubmatch(string(rr.Body)) + matches := idRegex.FindSubmatch(trace.ResponseBody) if len(matches) == 2 { - status.SetExternalID(matches[1]) + status.SetExternalID(string(matches[1])) } return status, nil diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index ac49ec7a8..991d38fa0 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -17,7 +17,6 @@ import ( "github.com/gomodule/redigo/redis" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" "github.com/sirupsen/logrus" ) @@ -190,14 +189,14 @@ func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) if err != nil { duration := time.Now().Sub(start) logs = append(logs, courier.NewChannelLogFromError("failed to fetch access token", channel, courier.NilMsgID, duration, err)) return h.Backend().WriteChannelLogs(ctx, logs) } - accessToken, err := jsonparser.GetString([]byte(rr.Body), "access_token") + accessToken, err := jsonparser.GetString(trace.ResponseBody, "access_token") if err != nil { duration := time.Now().Sub(start) logs = append(logs, courier.NewChannelLogFromError("invalid json", channel, courier.NilMsgID, duration, err)) @@ -263,10 +262,11 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken)) - rr, err := utils.MakeHTTPRequest(req) + + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { @@ -297,11 +297,11 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn req, _ := http.NewRequest(http.MethodGet, reqURL.String(), nil) req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken)) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) if err != nil { - return nil, fmt.Errorf("unable to look up contact data:%s\n%s", err, rr.Response) + return nil, fmt.Errorf("unable to look up contact data: %s", err) } - nickname, _ := jsonparser.GetString(rr.Body, "nickname") + nickname, _ := jsonparser.GetString(trace.ResponseBody, "nickname") return map[string]string{"name": nickname}, nil } diff --git a/handlers/kannel/kannel.go b/handlers/kannel/kannel.go index e7b52995e..64b9605f8 100644 --- a/handlers/kannel/kannel.go +++ b/handlers/kannel/kannel.go @@ -10,8 +10,8 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/gsm7" + "github.com/nyaruka/gocommon/httpx" ) const ( @@ -200,23 +200,23 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat if err != nil { return nil, err } - var rr *utils.RequestResponse + var trace *httpx.Trace if verifySSL { - rr, err = utils.MakeHTTPRequest(req) + trace, err = handlers.MakeHTTPRequest(req) } else { - rr, err = utils.MakeInsecureHTTPRequest(req) + trace, err = handlers.MakeInsecureHTTPRequest(req) } // record our status and log status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - status.AddLog(courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err)) + status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) if err == nil { status.SetStatus(courier.MsgWired) } // kannel will respond with a 403 for non-routable numbers, fail permanently in these cases - if rr.StatusCode == 403 { + if trace.Response != nil && trace.Response.StatusCode == 403 { status.SetStatus(courier.MsgFailed) } diff --git a/handlers/line/line.go b/handlers/line/line.go index 924cb3ec2..b2df2610b 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -16,8 +16,6 @@ import ( "github.com/buger/jsonparser" - "github.com/nyaruka/courier/utils" - "github.com/nyaruka/gocommon/urns" "github.com/nyaruka/courier" @@ -332,8 +330,9 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat if err != nil { return status, err } - rr, err := utils.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + + trace, err := handlers.MakeHTTPRequest(req) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err == nil { @@ -342,14 +341,15 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat continue } // retry without the reply token if it's invalid - errMsg, err := jsonparser.GetString(rr.Body, "message") + errMsg, err := jsonparser.GetString(trace.ResponseBody, "message") if err == nil && errMsg == "Invalid reply token" { req, err = buildSendMsgRequest(authToken, msg.URN().Path(), "", batch) if err != nil { return status, err } - rr, err = utils.MakeHTTPRequest(req) - log = courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + + trace, err = handlers.MakeHTTPRequest(req) + log = courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, err diff --git a/handlers/m3tech/m3tech.go b/handlers/m3tech/m3tech.go index e38daaf85..3c18e9a49 100644 --- a/handlers/m3tech/m3tech.go +++ b/handlers/m3tech/m3tech.go @@ -10,7 +10,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/gsm7" ) @@ -113,8 +112,9 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat if err != nil { return nil, err } - rr, err := utils.MakeHTTPRequest(req) - status.AddLog(courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err)) + + trace, err := handlers.MakeHTTPRequest(req) + status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) if err != nil { break } diff --git a/handlers/macrokiosk/macrokiosk.go b/handlers/macrokiosk/macrokiosk.go index 6baa0f029..b7127e71f 100644 --- a/handlers/macrokiosk/macrokiosk.go +++ b/handlers/macrokiosk/macrokiosk.go @@ -11,7 +11,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/gsm7" "github.com/buger/jsonparser" @@ -192,14 +191,14 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + trace, err := handlers.MakeHTTPRequest(req) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } - externalID, err := jsonparser.GetString([]byte(rr.Body), "MsgID") + externalID, err := jsonparser.GetString(trace.ResponseBody, "MsgID") if err != nil { return status, fmt.Errorf("unable to parse response body from Macrokiosk") } diff --git a/handlers/mblox/mblox.go b/handlers/mblox/mblox.go index a323003df..74bdd7882 100644 --- a/handlers/mblox/mblox.go +++ b/handlers/mblox/mblox.go @@ -13,7 +13,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" ) var ( @@ -144,14 +143,14 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", password)) - rr, err := utils.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + trace, err := handlers.MakeHTTPRequest(req) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } - externalID, err := jsonparser.GetString([]byte(rr.Body), "id") + externalID, err := jsonparser.GetString(trace.ResponseBody, "id") if err != nil { return status, fmt.Errorf("unable to parse response body from MBlox") } diff --git a/handlers/messangi/messangi.go b/handlers/messangi/messangi.go index 988890a12..88c213afb 100644 --- a/handlers/messangi/messangi.go +++ b/handlers/messangi/messangi.go @@ -90,14 +90,14 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat fullURL := fmt.Sprintf("%s/%s/%s/%s", sendURL, params, publicKey, signature) req, err := http.NewRequest(http.MethodGet, fullURL, nil) - if err != nil { return nil, err } - rr, err := utils.MakeHTTPRequest(req) + + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil @@ -105,7 +105,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat // parse our response as XML response := &mtResponse{} - err = xml.Unmarshal(rr.Body, response) + err = xml.Unmarshal(trace.ResponseBody, response) if err != nil { log.WithError("Message Send Error", err) break diff --git a/handlers/mtarget/mtarget.go b/handlers/mtarget/mtarget.go index 90582b823..724c08091 100644 --- a/handlers/mtarget/mtarget.go +++ b/handlers/mtarget/mtarget.go @@ -13,7 +13,6 @@ import ( "github.com/gomodule/redigo/redis" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" ) var ( @@ -181,8 +180,8 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat return nil, err } - rr, err := utils.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + trace, err := handlers.MakeHTTPRequest(req) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { break @@ -198,8 +197,8 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat // "ticket": "760eeaa0-5034-11e7-bb92-00000a0a643a" // }] // } - code, _ := jsonparser.GetString(rr.Body, "results", "[0]", "code") - externalID, _ := jsonparser.GetString(rr.Body, "results", "[0]", "ticket") + code, _ := jsonparser.GetString(trace.ResponseBody, "results", "[0]", "code") + externalID, _ := jsonparser.GetString(trace.ResponseBody, "results", "[0]", "ticket") if code == "0" && externalID != "" { // all went well, set ourselves to wired status.SetStatus(courier.MsgWired) diff --git a/handlers/nexmo/nexmo.go b/handlers/nexmo/nexmo.go index 812d880bd..c63d0555d 100644 --- a/handlers/nexmo/nexmo.go +++ b/handlers/nexmo/nexmo.go @@ -12,8 +12,8 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/gsm7" + "github.com/nyaruka/gocommon/httpx" "github.com/buger/jsonparser" "github.com/pkg/errors" @@ -153,7 +153,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat "type": []string{textType}, } - var rr *utils.RequestResponse + var trace *httpx.Trace var requestErr error for i := 0; i < 3; i++ { req, err := http.NewRequest(http.MethodPost, sendURL, strings.NewReader(form.Encode())) @@ -162,8 +162,8 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - rr, requestErr = utils.MakeHTTPRequest(req) - matched := throttledRE.FindAllStringSubmatch(string([]byte(rr.Body)), -1) + trace, requestErr = handlers.MakeHTTPRequest(req) + matched := throttledRE.FindAllStringSubmatch(string(trace.ResponseBody), -1) if len(matched) > 0 && len(matched[0]) > 0 { sleepTime, _ := strconv.Atoi(matched[0][1]) time.Sleep(time.Duration(sleepTime) * time.Millisecond) @@ -173,20 +173,20 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace) status.AddLog(log) if requestErr != nil { log.WithError("Message Send Error", requestErr) return status, nil } - nexmoStatus, err := jsonparser.GetString([]byte(rr.Body), "messages", "[0]", "status") + nexmoStatus, err := jsonparser.GetString(trace.ResponseBody, "messages", "[0]", "status") if err != nil || nexmoStatus != "0" { log.WithError("Message Send Error", errors.Errorf("failed to send message, received error status [%s]", nexmoStatus)) return status, nil } - externalID, err := jsonparser.GetString([]byte(rr.Body), "messages", "[0]", "message-id") + externalID, err := jsonparser.GetString(trace.ResponseBody, "messages", "[0]", "message-id") if err == nil { status.SetExternalID(externalID) } diff --git a/handlers/novo/novo.go b/handlers/novo/novo.go index 32180c425..4c2f20d4f 100644 --- a/handlers/novo/novo.go +++ b/handlers/novo/novo.go @@ -109,16 +109,17 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat if err != nil { return nil, err } - rr, err := utils.MakeHTTPRequest(req) + + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } - responseMsgStatus, _ := jsonparser.GetString(rr.Body, "status") + responseMsgStatus, _ := jsonparser.GetString(trace.ResponseBody, "status") // we always get 204 on success if responseMsgStatus == "FINISHED" { diff --git a/handlers/playmobile/playmobile.go b/handlers/playmobile/playmobile.go index 6f45f7cc2..8499727be 100644 --- a/handlers/playmobile/playmobile.go +++ b/handlers/playmobile/playmobile.go @@ -12,7 +12,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" ) const ( @@ -197,16 +196,16 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } - if rr.StatusCode == 200 { + if trace.Response != nil && trace.Response.StatusCode == 200 { status.SetStatus(courier.MsgWired) } else { log.WithError("Message Send Error", fmt.Errorf("received invalid response")) diff --git a/handlers/plivo/plivo.go b/handlers/plivo/plivo.go index 869046068..49384c3af 100644 --- a/handlers/plivo/plivo.go +++ b/handlers/plivo/plivo.go @@ -17,7 +17,6 @@ import ( "strings" "github.com/buger/jsonparser" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" @@ -171,14 +170,14 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.SetBasicAuth(authID, authToken) - rr, err := utils.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + trace, err := handlers.MakeHTTPRequest(req) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } - externalID, err := jsonparser.GetString(rr.Body, "message_uuid", "[0]") + externalID, err := jsonparser.GetString(trace.ResponseBody, "message_uuid", "[0]") if err != nil { return status, fmt.Errorf("unable to parse response body from Plivo") } diff --git a/handlers/redrabbit/redrabbit.go b/handlers/redrabbit/redrabbit.go index c857605dd..e0ba6fda1 100644 --- a/handlers/redrabbit/redrabbit.go +++ b/handlers/redrabbit/redrabbit.go @@ -9,7 +9,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/gsm7" ) @@ -69,12 +68,12 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat msgURL, _ := url.Parse(sendURL) msgURL.RawQuery = form.Encode() req, err := http.NewRequest(http.MethodGet, msgURL.String(), nil) - if err != nil { return nil, err } - rr, err := utils.MakeHTTPRequest(req) - status.AddLog(courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err)) + + trace, err := handlers.MakeHTTPRequest(req) + status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) if err != nil { return status, nil } diff --git a/handlers/rocketchat/rocketchat.go b/handlers/rocketchat/rocketchat.go index acbb8c84c..50dc9e191 100644 --- a/handlers/rocketchat/rocketchat.go +++ b/handlers/rocketchat/rocketchat.go @@ -6,12 +6,12 @@ import ( "encoding/json" "errors" "fmt" + "net/http" + "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" - "net/http" ) const ( @@ -139,16 +139,16 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Token %s", secret)) - res, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), res).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, err } - msgID, err := jsonparser.GetString(res.Body, "id") + msgID, err := jsonparser.GetString(trace.ResponseBody, "id") if err == nil { status.SetExternalID(msgID) } diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index 21ea590a5..ca3eca12c 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -119,15 +119,15 @@ func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file req.Header.Add("Content-Type", "application/json; charset=utf-8") req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", userToken)) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) if err != nil { - log := courier.NewChannelLogFromRR("File Resolving", channel, courier.NilMsgID, rr).WithError("File Resolving Error", err) + log := courier.NewChannelLogFromTrace("File Resolving", channel, courier.NilMsgID, trace).WithError("File Resolving Error", err) h.Backend().WriteChannelLogs(ctx, []*courier.ChannelLog{log}) return "", err } var fResponse FileResponse - if err := json.Unmarshal([]byte(rr.Body), &fResponse); err != nil { + if err := json.Unmarshal(trace.ResponseBody, &fResponse); err != nil { return "", errors.Errorf("couldn't unmarshal file response: %v", err) } @@ -205,17 +205,17 @@ func sendTextMsgPart(msg courier.Msg, token string) (*courier.ChannelLog, error) req.Header.Set("Content-Type", "application/json; charset=utf-8") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - ok, err := jsonparser.GetBoolean([]byte(rr.Body), "ok") + ok, err := jsonparser.GetBoolean(trace.ResponseBody, "ok") if err != nil { return log, err } if !ok { - errDescription, err := jsonparser.GetString([]byte(rr.Body), "error") + errDescription, err := jsonparser.GetString(trace.ResponseBody, "error") if err != nil { return log, err } @@ -231,15 +231,16 @@ func parseAttachmentToFileParams(msg courier.Msg, attachment string) (*FileParam if err != nil { return nil, nil, errors.Wrapf(err, "error building file request") } - resp, err := utils.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Fetching attachment", msg.Channel(), msg.ID(), resp).WithError("error fetching media", err) + + trace, err := handlers.MakeHTTPRequest(req) + log := courier.NewChannelLogFromTrace("Fetching attachment", msg.Channel(), msg.ID(), trace).WithError("error fetching media", err) filename, err := utils.BasePathForURL(attURL) if err != nil { return nil, log, err } return &FileParams{ - File: resp.Body, + File: trace.ResponseBody, FileName: filename, Channels: msg.URN().Path(), }, log, nil @@ -276,13 +277,14 @@ func sendFilePart(msg courier.Msg, token string, fileParams *FileParams) (*couri } req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) req.Header.Add("Content-Type", writer.FormDataContentType()) - resp, err := utils.MakeHTTPRequest(req) + + trace, err := handlers.MakeHTTPRequest(req) if err != nil { return nil, errors.Wrapf(err, "error uploading file to slack") } var fr FileResponse - if err := json.Unmarshal([]byte(resp.Body), &fr); err != nil { + if err := json.Unmarshal(trace.ResponseBody, &fr); err != nil { return nil, errors.Errorf("couldn't unmarshal file response: %v", err) } @@ -290,7 +292,7 @@ func sendFilePart(msg courier.Msg, token string, fileParams *FileParams) (*couri return nil, errors.Errorf("error uploading file to slack: %s.", fr.Error) } - return courier.NewChannelLogFromRR("uploading file to Slack", msg.Channel(), msg.ID(), resp).WithError("Error uploading file to Slack", err), nil + return courier.NewChannelLogFromTrace("uploading file to Slack", msg.Channel(), msg.ID(), trace).WithError("Error uploading file to Slack", err), nil } // DescribeURN handles Slack user details @@ -307,13 +309,13 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn q.Add("user", urn.Path()) req.URL.RawQuery = q.Encode() - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) if err != nil { - return nil, fmt.Errorf("request user info error:%s\n%s", err, rr.Response) + return nil, fmt.Errorf("request user info error: %s", err) } var uInfo *UserInfo - if err := json.Unmarshal(rr.Body, &uInfo); err != nil { + if err := json.Unmarshal(trace.ResponseBody, &uInfo); err != nil { return nil, fmt.Errorf("unmarshal user info error:%s", err) } diff --git a/handlers/smscentral/smscentral.go b/handlers/smscentral/smscentral.go index 85f23b4af..0d711540b 100644 --- a/handlers/smscentral/smscentral.go +++ b/handlers/smscentral/smscentral.go @@ -9,7 +9,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/pkg/errors" ) @@ -90,17 +89,17 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - status.AddLog(courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err)) + status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) if err != nil { return status, nil } - if rr.StatusCode/100 != 2 { - return status, errors.Errorf("Got non-200 response [%d] from API", rr.StatusCode) + if trace.Response.StatusCode/100 != 2 { + return status, errors.Errorf("Got non-200 response [%d] from API", trace.Response.StatusCode) } status.SetStatus(courier.MsgWired) diff --git a/handlers/start/start.go b/handlers/start/start.go index bf2cf254a..59d10bc88 100644 --- a/handlers/start/start.go +++ b/handlers/start/start.go @@ -14,8 +14,6 @@ import ( "strconv" "time" - "github.com/nyaruka/courier/utils" - "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" ) @@ -165,9 +163,9 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/xml; charset=utf8") req.SetBasicAuth(username, password) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace) status.AddLog(log) if err != nil { log.WithError("Message Send Error", err) @@ -175,7 +173,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } response := &mtResponse{} - err = xml.Unmarshal(rr.Body, response) + err = xml.Unmarshal(trace.ResponseBody, response) if err == nil { status.SetStatus(courier.MsgWired) if i == 0 { diff --git a/handlers/telesom/telesom.go b/handlers/telesom/telesom.go index fd771ec5e..9a3d98421 100644 --- a/handlers/telesom/telesom.go +++ b/handlers/telesom/telesom.go @@ -11,7 +11,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/dates" ) @@ -115,18 +114,18 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - rr, err := utils.MakeInsecureHTTPRequest(req) + trace, err := handlers.MakeInsecureHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } - if strings.Contains(string(rr.Body), "Success") { + if strings.Contains(string(trace.ResponseBody), "Success") { status.SetStatus(courier.MsgWired) } else { - log.WithError("Message Send Error", fmt.Errorf("Received invalid response content: %s", string(rr.Body))) + log.WithError("Message Send Error", fmt.Errorf("Received invalid response content: %s", string(trace.ResponseBody))) } } return status, nil diff --git a/handlers/thinq/thinq.go b/handlers/thinq/thinq.go index 834a6e7c3..626cd3976 100644 --- a/handlers/thinq/thinq.go +++ b/handlers/thinq/thinq.go @@ -12,7 +12,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" ) const configAccountID = "account_id" @@ -166,17 +165,17 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus req.Header.Set("Accept", "application/json") req.SetBasicAuth(tokenUser, token) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } // try to get our external id - externalID, err := jsonparser.GetString([]byte(rr.Body), "guid") + externalID, err := jsonparser.GetString(trace.ResponseBody, "guid") if err != nil { log.WithError("Unable to read external ID", err) return status, nil @@ -202,17 +201,18 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") req.SetBasicAuth(tokenUser, token) - rr, err := utils.MakeHTTPRequest(req) + + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } // get our external id - externalID, err := jsonparser.GetString([]byte(rr.Body), "guid") + externalID, err := jsonparser.GetString(trace.ResponseBody, "guid") if err != nil { log.WithError("Unable to read external ID from guid field", err) return status, nil diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index ce39b0769..ac8db61ca 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -266,15 +266,15 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) // see if we can parse the error if we have one - if err != nil && rr.Body != nil { - errorCode, _ := jsonparser.GetInt([]byte(rr.Body), "code") + if err != nil && len(trace.ResponseBody) > 0 { + errorCode, _ := jsonparser.GetInt(trace.ResponseBody, "code") if errorCode != 0 { if errorCode == errorStopped { status.SetStatus(courier.MsgFailed) @@ -297,7 +297,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } // grab the external id - externalID, err := jsonparser.GetString([]byte(rr.Body), "sid") + externalID, err := jsonparser.GetString(trace.ResponseBody, "sid") if err != nil { log.WithError("Message Send Error", errors.Errorf("unable to get sid from body")) return status, nil diff --git a/handlers/twitter/twitter.go b/handlers/twitter/twitter.go index 4f41a4a65..92185ceb2 100644 --- a/handlers/twitter/twitter.go +++ b/handlers/twitter/twitter.go @@ -345,16 +345,16 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req, _ := http.NewRequest(http.MethodPost, sendURL, bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequestWithClient(req, client) + trace, err := handlers.MakeHTTPRequestWithClient(client, req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } - externalID, err := jsonparser.GetString(rr.Body, "event", "id") + externalID, err := jsonparser.GetString(trace.ResponseBody, "event", "id") if err != nil { log.WithError("Message Send Error", errors.Errorf("unable to get message_id from body")) return status, nil @@ -387,8 +387,8 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s // retrieve the media to be sent from S3 req, _ := http.NewRequest(http.MethodGet, attachmentURL, nil) - s3rr, err := utils.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Media Fetch", msg.Channel(), msg.ID(), s3rr) + s3Trace, err := handlers.MakeHTTPRequest(req) + log := courier.NewChannelLogFromTrace("Media Fetch", msg.Channel(), msg.ID(), s3Trace) if err != nil { log.WithError("Media Fetch Error", err) logs = append(logs, log) @@ -403,7 +403,7 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s mediaCategory = "dm_video" } - fileSize := int64(len(s3rr.Body)) + fileSize := int64(len(s3Trace.ResponseBody)) // upload it to WhatsApp in exchange for a media id form := url.Values{ @@ -420,8 +420,9 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s twReq.Header.Set("Content-Type", "application/x-www-form-urlencoded") twReq.Header.Set("Accept", "application/json") twReq.Header.Set("User-Agent", utils.HTTPUserAgent) - twrr, err := utils.MakeHTTPRequestWithClient(twReq, client) - log = courier.NewChannelLogFromRR("Media Upload INIT", msg.Channel(), msg.ID(), twrr) + + twTrace, err := handlers.MakeHTTPRequestWithClient(client, twReq) + log = courier.NewChannelLogFromTrace("Media Upload INIT", msg.Channel(), msg.ID(), twTrace) if err != nil { log.WithError("Media Upload INIT Error", err) logs = append(logs, log) @@ -429,7 +430,7 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s } logs = append(logs, log) - mediaID, err := jsonparser.GetString(twrr.Body, "media_id_string") + mediaID, err := jsonparser.GetString(twTrace.ResponseBody, "media_id_string") if err != nil { duration := time.Now().Sub(start) logs = append(logs, courier.NewChannelLogFromError("Media Upload media_id Error", msg.Channel(), msg.ID(), duration, err)) @@ -460,7 +461,7 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s } mediaWriter, err := bodyMultipartWriter.CreateFormFile("media", fileName) - _, err = io.Copy(mediaWriter, bytes.NewReader(s3rr.Body)) + _, err = io.Copy(mediaWriter, bytes.NewReader(s3Trace.ResponseBody)) if err != nil { duration := time.Now().Sub(start) logs = append(logs, courier.NewChannelLogFromError("Media Upload APPEND field media Error", msg.Channel(), msg.ID(), duration, err)) @@ -474,8 +475,8 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s twReq.Header.Set("Content-Type", contentType) twReq.Header.Set("Accept", "application/json") twReq.Header.Set("User-Agent", utils.HTTPUserAgent) - twrr, err = utils.MakeHTTPRequestWithClient(twReq, client) - log = courier.NewChannelLogFromRR("Media Upload APPEND request", msg.Channel(), msg.ID(), twrr) + twTrace, err = handlers.MakeHTTPRequestWithClient(client, twReq) + log = courier.NewChannelLogFromTrace("Media Upload APPEND request", msg.Channel(), msg.ID(), twTrace) if err != nil { log = log.WithError("Media Upload APPEND request Error", err) logs = append(logs, log) @@ -494,9 +495,9 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s twReq.Header.Set("Content-Type", "application/x-www-form-urlencoded") twReq.Header.Set("Accept", "application/json") twReq.Header.Set("User-Agent", utils.HTTPUserAgent) - twrr, err = utils.MakeHTTPRequestWithClient(twReq, client) + twTrace, err = handlers.MakeHTTPRequestWithClient(client, twReq) - log = courier.NewChannelLogFromRR("Media Upload FINALIZE", msg.Channel(), msg.ID(), twrr) + log = courier.NewChannelLogFromTrace("Media Upload FINALIZE", msg.Channel(), msg.ID(), twTrace) if err != nil { log.WithError("Media Upload FINALIZE Error", err) @@ -505,14 +506,14 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s } logs = append(logs, log) - progressState, err := jsonparser.GetString(twrr.Body, "processing_info", "state") + progressState, err := jsonparser.GetString(twTrace.ResponseBody, "processing_info", "state") if err != nil { return mediaID, logs, nil } for { - checkAfter, err := jsonparser.GetInt(twrr.Body, "processing_info", "check_after_secs") + checkAfter, err := jsonparser.GetInt(twTrace.ResponseBody, "processing_info", "check_after_secs") if err != nil { return "", logs, err @@ -531,14 +532,15 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s twReq.Header.Set("Content-Type", "application/x-www-form-urlencoded") twReq.Header.Set("Accept", "application/json") twReq.Header.Set("User-Agent", utils.HTTPUserAgent) - twrr, err = utils.MakeHTTPRequestWithClient(twReq, client) - log = courier.NewChannelLogFromRR("Media Upload STATUS", msg.Channel(), msg.ID(), twrr) + + twTrace, err = handlers.MakeHTTPRequestWithClient(client, twReq) + log = courier.NewChannelLogFromTrace("Media Upload STATUS", msg.Channel(), msg.ID(), twTrace) if err != nil { log.WithError("Media Upload STATUS Error", err) logs = append(logs, log) return "", logs, err } - progressState, err = jsonparser.GetString(twrr.Body, "processing_info", "state") + progressState, err = jsonparser.GetString(twTrace.ResponseBody, "processing_info", "state") if err != nil { log.WithError("Media Upload STATUS failed parse JSON", err) logs = append(logs, log) diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index 8b0ec7060..1a4dc2c56 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -10,13 +10,13 @@ import ( "fmt" "io/ioutil" "net/http" + "strconv" "strings" "time" "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" "github.com/pkg/errors" ) @@ -346,6 +346,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat attURL := "" filename := "" msgText := "" + var err error if i < len(msg.Attachments()) { mediaType, mediaURL := handlers.SplitAttachment(msg.Attachments()[0]) @@ -358,30 +359,19 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat case "video": msgType = "video" attURL = mediaURL - req, err := http.NewRequest(http.MethodHead, mediaURL, nil) + attSize, err = getAttachmentSize(mediaURL) if err != nil { return nil, err } - rr, err := utils.MakeHTTPRequest(req) - if err != nil { - return nil, err - } - - attSize = rr.ContentLength msgText = "" case "audio": msgType = "file" attURL = mediaURL - req, err := http.NewRequest(http.MethodHead, mediaURL, nil) - if err != nil { - return nil, err - } - rr, err := utils.MakeHTTPRequest(req) + attSize, err = getAttachmentSize(mediaURL) if err != nil { return nil, err } - attSize = rr.ContentLength filename = "Audio" msgText = "" @@ -411,7 +401,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } requestBody := &bytes.Buffer{} - err := json.NewEncoder(requestBody).Encode(payload) + err = json.NewEncoder(requestBody).Encode(payload) if err != nil { return nil, err } @@ -424,16 +414,16 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, nil } - responseStatus, err := jsonparser.GetInt(rr.Body, "status") + responseStatus, err := jsonparser.GetInt(trace.ResponseBody, "status") if err != nil { log.WithError("Message Send Error", errors.Errorf("received invalid JSON response")) return status, nil @@ -448,3 +438,26 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } return status, nil } + +func getAttachmentSize(u string) (int, error) { + req, err := http.NewRequest(http.MethodHead, u, nil) + if err != nil { + return 0, err + } + + trace, err := handlers.MakeHTTPRequest(req) + if err != nil { + return 0, err + } + + contentLenHdr := trace.Response.Header.Get("Content-Length") + + if trace.Response.Header.Get("Content-Length") != "" { + contentLength, err := strconv.Atoi(contentLenHdr) + if err == nil { + return contentLength, nil + } + } + + return 0, nil +} diff --git a/handlers/vk/vk.go b/handlers/vk/vk.go index 9011088d9..dc80a014a 100644 --- a/handlers/vk/vk.go +++ b/handlers/vk/vk.go @@ -284,17 +284,18 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn params.Set(paramUserIds, urnPath) req.URL.RawQuery = params.Encode() - res, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) if err != nil { return nil, err } + // parsing response type responsePayload struct { Users []userPayload `json:"response" validate:"required"` } payload := &responsePayload{} - err = json.Unmarshal(res.Body, payload) + err = json.Unmarshal(trace.ResponseBody, payload) if err != nil { return nil, err @@ -404,21 +405,21 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } req, err := http.NewRequest(http.MethodPost, apiBaseURL+actionSendMessage, nil) - if err != nil { return status, errors.New("Cannot create send message request") } req.URL.RawQuery = params.Encode() - res, err := utils.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), res).WithError("Message Send Error", err) + trace, err := handlers.MakeHTTPRequest(req) + + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { return status, err } - externalMsgId, err := jsonparser.GetInt(res.Body, responseOutgoingMessageKey) + externalMsgId, err := jsonparser.GetInt(trace.ResponseBody, responseOutgoingMessageKey) if err != nil { return status, errors.Errorf("no '%s' value in response", responseOutgoingMessageKey) @@ -516,14 +517,15 @@ func getUploadServerURL(channel courier.Channel, sendURL string) (string, error) } params := buildApiBaseParams(channel) req.URL.RawQuery = params.Encode() - res, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) if err != nil { return "", err } + uploadServer := &uploadServerPayload{} - if err = json.Unmarshal(res.Body, uploadServer); err != nil { + if err = json.Unmarshal(trace.ResponseBody, uploadServer); err != nil { return "", nil } return uploadServer.Server.UploadURL, nil @@ -547,34 +549,34 @@ func downloadMedia(mediaURL string) (io.Reader, error) { func uploadMedia(serverURL, uploadKey, mediaExt string, media io.Reader) ([]byte, error) { body := &bytes.Buffer{} writer := multipart.NewWriter(body) - fileName := fmt.Sprintf("%s.%s", uploadKey, mediaExt) - part, err := writer.CreateFormFile(uploadKey, fileName) + part, err := writer.CreateFormFile(uploadKey, fileName) if err != nil { return nil, err } - _, err = io.Copy(part, media) + _, err = io.Copy(part, media) if err != nil { return nil, err } - err = writer.Close() + err = writer.Close() if err != nil { return nil, err } - req, err := http.NewRequest(http.MethodPost, serverURL, body) + req, err := http.NewRequest(http.MethodPost, serverURL, body) if err != nil { return nil, err } + req.Header.Set("Content-Type", writer.FormDataContentType()) - if res, err := utils.MakeHTTPRequest(req); err != nil { + if trace, err := handlers.MakeHTTPRequest(req); err != nil { return nil, err } else { - return res.Body, nil + return trace.ResponseBody, nil } } @@ -584,17 +586,19 @@ func saveUploadedMediaInfo(channel courier.Channel, sendURL, serverId, hash, med params.Set(paramServerId, serverId) params.Set(paramHash, hash) params.Set(mediaKey, mediaValue) - req, err := http.NewRequest(http.MethodPost, sendURL, nil) + req, err := http.NewRequest(http.MethodPost, sendURL, nil) if err != nil { return nil, err } + req.URL.RawQuery = params.Encode() - res, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) if err != nil { return nil, err } + // parsing response type responsePayload struct { Response []mediaUploadInfoPayload `json:"response"` @@ -602,7 +606,7 @@ func saveUploadedMediaInfo(channel courier.Channel, sendURL, serverId, hash, med medias := &responsePayload{} // try get first object - if err = json.Unmarshal(res.Body, medias); err != nil || len(medias.Response) == 0 { + if err = json.Unmarshal(trace.ResponseBody, medias); err != nil || len(medias.Response) == 0 { return nil, errors.New("no response") } else { return &medias.Response[0], nil diff --git a/handlers/wavy/wavy.go b/handlers/wavy/wavy.go index 73cdf5885..8315d8afc 100644 --- a/handlers/wavy/wavy.go +++ b/handlers/wavy/wavy.go @@ -12,7 +12,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" ) var ( @@ -171,15 +170,15 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("username", username) req.Header.Set("authenticationtoken", token) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - status.AddLog(courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err)) + status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) if err != nil { return status, nil } - externalID, _ := jsonparser.GetString(rr.Body, "id") + externalID, _ := jsonparser.GetString(trace.ResponseBody, "id") if externalID != "" { status.SetExternalID(externalID) } diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index 97f185477..d93a158db 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -17,7 +17,6 @@ import ( "github.com/gomodule/redigo/redis" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" "github.com/sirupsen/logrus" ) @@ -112,20 +111,21 @@ func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) req, _ := http.NewRequest(http.MethodGet, tokenURL.String(), nil) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) + + trace, err := handlers.MakeHTTPRequest(req) if err != nil { duration := time.Now().Sub(start) logs = append(logs, courier.NewChannelLogFromError("failed to fetch access token", channel, courier.NilMsgID, duration, err)) return h.Backend().WriteChannelLogs(ctx, logs) } - accessToken, err := jsonparser.GetString(rr.Body, "access_token") + accessToken, err := jsonparser.GetString(trace.ResponseBody, "access_token") if err != nil { duration := time.Now().Sub(start) logs = append(logs, courier.NewChannelLogFromError("invalid json", channel, courier.NilMsgID, duration, err)) return h.Backend().WriteChannelLogs(ctx, logs) } - expiration, err := jsonparser.GetInt(rr.Body, "expires_in") + expiration, err := jsonparser.GetInt(trace.ResponseBody, "expires_in") if err != nil { expiration = 7200 } @@ -268,10 +268,10 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) status.AddLog(log) if err != nil { @@ -302,11 +302,11 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn req, _ := http.NewRequest(http.MethodGet, reqURL.String(), nil) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) if err != nil { - return nil, fmt.Errorf("unable to look up contact data:%s\n%s", err, rr.Response) + return nil, fmt.Errorf("unable to look up contact data: %s", err) } - nickname, err := jsonparser.GetString(rr.Body, "nickname") + nickname, err := jsonparser.GetString(trace.ResponseBody, "nickname") if err != nil { return nil, err } diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index ba93abe03..fcacf88f6 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -883,8 +883,9 @@ func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string) (stri if err != nil { return "", logs, errors.Wrapf(err, "error building media request") } - rr, err := utils.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Fetching media", msg.Channel(), msg.ID(), rr).WithError("error fetching media", err) + + trace, err := handlers.MakeHTTPRequest(req) + log := courier.NewChannelLogFromTrace("Fetching media", msg.Channel(), msg.ID(), trace).WithError("error fetching media", err) logs = append(logs, log) if err != nil { failedMediaCache.Set(failKey, true, cache.DefaultExpiration) @@ -899,14 +900,15 @@ func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string) (stri } dockerMediaURL, _ := url.Parse("/v1/media") - req, err = http.NewRequest("POST", dockerMediaURL.String(), bytes.NewReader(rr.Body)) + req, err = http.NewRequest("POST", dockerMediaURL.String(), bytes.NewReader(trace.ResponseBody)) if err != nil { return "", logs, errors.Wrapf(err, "error building request to media endpoint") } setWhatsAppAuthHeader(&req.Header, msg.Channel()) - req.Header.Add("Content-Type", httpx.DetectContentType(rr.Body)) - rr, err = utils.MakeHTTPRequest(req) - log = courier.NewChannelLogFromRR("Uploading media to WhatsApp", msg.Channel(), msg.ID(), rr).WithError("Error uploading media to WhatsApp", err) + req.Header.Add("Content-Type", httpx.DetectContentType(trace.ResponseBody)) + + trace, err = handlers.MakeHTTPRequest(req) + log = courier.NewChannelLogFromTrace("Uploading media to WhatsApp", msg.Channel(), msg.ID(), trace).WithError("Error uploading media to WhatsApp", err) logs = append(logs, log) if err != nil { failedMediaCache.Set(failKey, true, cache.DefaultExpiration) @@ -914,7 +916,7 @@ func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string) (stri } // take uploaded media id - mediaID, err = jsonparser.GetString(rr.Body, "media", "[0]", "id") + mediaID, err = jsonparser.GetString(trace.ResponseBody, "media", "[0]", "id") if err != nil { return "", logs, errors.Wrapf(err, "error reading media id from response") } @@ -939,9 +941,9 @@ func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload } req, _ := http.NewRequest(http.MethodPost, sendPath.String(), bytes.NewReader(jsonBody)) req.Header = buildWhatsAppHeaders(msg.Channel()) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) - if rr.StatusCode == 429 || rr.StatusCode == 503 { + if trace.Response != nil && (trace.Response.StatusCode == 429 || trace.Response.StatusCode == 503) { rateLimitKey := fmt.Sprintf("rate_limit:%s", msg.Channel().UUID().String()) rc.Do("SET", rateLimitKey, "engaged") @@ -950,13 +952,13 @@ func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload // TODO: In the future we should the header value when available rc.Do("EXPIRE", rateLimitKey, 2) - log := courier.NewChannelLogFromRR("rate limit engaged", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("rate limit engaged", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) return "", "", []*courier.ChannelLog{log}, err } - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) errPayload := &mtErrorPayload{} - err = json.Unmarshal(rr.Body, errPayload) + err = json.Unmarshal(trace.ResponseBody, errPayload) // handle send msg errors if err == nil && len(errPayload.Errors) > 0 { @@ -985,13 +987,13 @@ func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload checkLog := courier.NewChannelLogFromError("unable to build contact check request", msg.Channel(), msg.ID(), elapsed, err) return "", "", []*courier.ChannelLog{log, checkLog}, err } - checkLog := courier.NewChannelLogFromRR("Contact check", msg.Channel(), msg.ID(), rrCheck).WithError("Status Error", err) + checkLog := courier.NewChannelLogFromTrace("Contact check", msg.Channel(), msg.ID(), rrCheck).WithError("Status Error", err) if err != nil { return "", "", []*courier.ChannelLog{log, checkLog}, err } // update contact URN and msg destiny with returned wpp id - wppID, err := jsonparser.GetString(rrCheck.Body, "contacts", "[0]", "wa_id") + wppID, err := jsonparser.GetString(rrCheck.ResponseBody, "contacts", "[0]", "wa_id") if err == nil { var updatedPayload interface{} @@ -1043,20 +1045,20 @@ func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload reqRetry.URL.RawQuery = fmt.Sprintf("%s=1", retryParam) } - rrRetry, err := utils.MakeHTTPRequest(reqRetry) - retryLog := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rrRetry).WithError("Message Send Error", err) + traceRetry, err := handlers.MakeHTTPRequest(reqRetry) + retryLog := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), traceRetry).WithError("Message Send Error", err) if err != nil { return "", "", []*courier.ChannelLog{log, checkLog, retryLog}, err } - externalID, err := getSendWhatsAppMsgId(rrRetry) + externalID, err := getSendWhatsAppMsgId(traceRetry.ResponseBody) return wppID, externalID, []*courier.ChannelLog{log, checkLog, retryLog}, err } - externalID, err := getSendWhatsAppMsgId(rr) + externalID, err := getSendWhatsAppMsgId(trace.ResponseBody) if err != nil { return "", "", []*courier.ChannelLog{log}, err } - wppID, err := jsonparser.GetString(rr.Body, "contacts", "[0]", "wa_id") + wppID, err := jsonparser.GetString(trace.ResponseBody, "contacts", "[0]", "wa_id") if wppID != "" && wppID != msg.URN().Path() { return wppID, externalID, []*courier.ChannelLog{log}, err } @@ -1101,8 +1103,8 @@ func hasWhatsAppContactError(payload mtErrorPayload) bool { return false } -func getSendWhatsAppMsgId(rr *utils.RequestResponse) (string, error) { - if externalID, err := jsonparser.GetString(rr.Body, "messages", "[0]", "id"); err == nil { +func getSendWhatsAppMsgId(resp []byte) (string, error) { + if externalID, err := jsonparser.GetString(resp, "messages", "[0]", "id"); err == nil { return externalID, nil } else { return "", errors.Errorf("unable to get message id from response body") @@ -1115,7 +1117,7 @@ type mtContactCheckPayload struct { ForceCheck bool `json:"force_check"` } -func checkWhatsAppContact(channel courier.Channel, baseURL string, urn urns.URN) (*utils.RequestResponse, error) { +func checkWhatsAppContact(channel courier.Channel, baseURL string, urn urns.URN) (*httpx.Trace, error) { payload := mtContactCheckPayload{ Blocking: "wait", Contacts: []string{fmt.Sprintf("+%s", urn.Path())}, @@ -1129,20 +1131,20 @@ func checkWhatsAppContact(channel courier.Channel, baseURL string, urn urns.URN) sendURL := fmt.Sprintf("%s/v1/contacts", baseURL) req, _ := http.NewRequest(http.MethodPost, sendURL, bytes.NewReader(reqBody)) req.Header = buildWhatsAppHeaders(channel) - rr, err := utils.MakeHTTPRequest(req) + trace, err := handlers.MakeHTTPRequest(req) if err != nil { - return rr, err + return trace, err } // check contact status - if status, err := jsonparser.GetString(rr.Body, "contacts", "[0]", "status"); err == nil { + if status, err := jsonparser.GetString(trace.ResponseBody, "contacts", "[0]", "status"); err == nil { if status == "valid" { - return rr, nil + return trace, nil } else { - return rr, errors.Errorf(`contact status is "%s"`, status) + return trace, errors.Errorf(`contact status is "%s"`, status) } } else { - return rr, err + return trace, err } } diff --git a/server_test.go b/server_test.go index 461812f1f..cba8f1b4a 100644 --- a/server_test.go +++ b/server_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/nyaruka/courier/utils" + "github.com/nyaruka/gocommon/httpx" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" ) @@ -25,34 +25,34 @@ func TestServer(t *testing.T) { // hit our main pages, this is admitedly mostly in the name of coverage req, _ := http.NewRequest("GET", "http://localhost:8080/", nil) - rr, err := utils.MakeHTTPRequest(req) + trace, err := httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) assert.NoError(t, err) - assert.Contains(t, string(rr.Body), "courier") + assert.Contains(t, string(trace.ResponseBody), "courier") // status page without auth req, _ = http.NewRequest("GET", "http://localhost:8080/status", nil) - rr, err = utils.MakeHTTPRequest(req) - assert.Error(t, err) - assert.Equal(t, 401, rr.StatusCode) + trace, err = httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) + assert.NoError(t, err) + assert.Equal(t, 401, trace.Response.StatusCode) // status page with auth req, _ = http.NewRequest("GET", "http://localhost:8080/status", nil) req.SetBasicAuth("admin", "password123") - rr, err = utils.MakeHTTPRequest(req) + trace, err = httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) assert.NoError(t, err) - assert.Contains(t, string(rr.Body), "courier") + assert.Contains(t, string(trace.ResponseBody), "courier") // hit an invalid path req, _ = http.NewRequest("GET", "http://localhost:8080/notthere", nil) - rr, err = utils.MakeHTTPRequest(req) - assert.Error(t, err) - assert.Contains(t, string(rr.Body), "not found") + trace, err = httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) + assert.NoError(t, err) + assert.Contains(t, string(trace.ResponseBody), "not found") // invalid method req, _ = http.NewRequest("POST", "http://localhost:8080/", nil) - rr, err = utils.MakeHTTPRequest(req) - assert.Error(t, err) - assert.Contains(t, string(rr.Body), "method not allowed") + trace, err = httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) + assert.NoError(t, err) + assert.Contains(t, string(trace.ResponseBody), "method not allowed") } func TestSanitizeBody(t *testing.T) { diff --git a/utils/http.go b/utils/http.go index 1406a2589..cb11a5a0b 100644 --- a/utils/http.go +++ b/utils/http.go @@ -2,151 +2,11 @@ package utils import ( "crypto/tls" - "fmt" - "io/ioutil" "net/http" - "net/http/httputil" - "strconv" - "strings" "sync" "time" ) -// RequestResponseStatus represents the status of a WebhookRequeset -type RequestResponseStatus string - -// RequestResponse represents both the outgoing request and response for a particular URL/method/body -type RequestResponse struct { - Method string - URL string - Status RequestResponseStatus - StatusCode int - Request string - Response string - Body []byte - ContentLength int - Elapsed time.Duration -} - -const ( - // RRStatusSuccess represents that the webhook was successful - RRStatusSuccess RequestResponseStatus = "S" - - // RRConnectionFailure represents that the webhook had a connection failure - RRConnectionFailure RequestResponseStatus = "F" - - // RRStatusFailure represents that the webhook had a non 2xx status code - RRStatusFailure RequestResponseStatus = "E" -) - -// Deprecated: use handlers.MakeInsecureHTTPRequest instead -func MakeInsecureHTTPRequest(req *http.Request) (*RequestResponse, error) { - return MakeHTTPRequestWithClient(req, GetInsecureHTTPClient()) -} - -// Deprecated: use handlers.MakeHTTPRequest instead -func MakeHTTPRequest(req *http.Request) (*RequestResponse, error) { - return MakeHTTPRequestWithClient(req, GetHTTPClient()) -} - -// Deprecated: use handlers.MakeHTTPRequestWithClient instead -func MakeHTTPRequestWithClient(req *http.Request, client *http.Client) (*RequestResponse, error) { - req.Header.Set("User-Agent", HTTPUserAgent) - - start := time.Now() - requestTrace, err := httputil.DumpRequestOut(req, true) - if err != nil { - rr, _ := newRRFromRequestAndError(req, string(requestTrace), err) - return rr, err - } - - resp, err := client.Do(req) - if err != nil { - rr, _ := newRRFromRequestAndError(req, string(requestTrace), err) - return rr, err - } - defer resp.Body.Close() - - rr, err := newRRFromResponse(req.Method, string(requestTrace), resp) - rr.Elapsed = time.Now().Sub(start) - return rr, err -} - -// newRRFromResponse creates a new RequestResponse based on the passed in http request and error (when we received no response) -func newRRFromRequestAndError(r *http.Request, requestTrace string, requestError error) (*RequestResponse, error) { - rr := RequestResponse{ContentLength: -1} - rr.Method = r.Method - rr.URL = r.URL.String() - - rr.Request = requestTrace - rr.Status = RRConnectionFailure - rr.Body = []byte(requestError.Error()) - - return &rr, nil -} - -// newRRFromResponse creates a new RequestResponse based on the passed in http Response -func newRRFromResponse(method string, requestTrace string, r *http.Response) (*RequestResponse, error) { - var err error - rr := RequestResponse{ContentLength: -1} - rr.Method = method - rr.URL = r.Request.URL.String() - rr.StatusCode = r.StatusCode - - // set our content length if we have its header - - if r.Header.Get("Content-Length") != "" { - contentLength, err := strconv.Atoi(r.Header.Get("Content-Length")) - if err == nil { - rr.ContentLength = contentLength - } - } - - // set our status based on our status code - if rr.StatusCode/100 == 2 { - rr.Status = RRStatusSuccess - } else { - rr.Status = RRStatusFailure - } - - rr.Request = requestTrace - - // figure out if our Response is something that looks like text from our headers - isText := false - contentType := r.Header.Get("Content-Type") - if contentType == "" || - strings.Contains(contentType, "text") || - strings.Contains(contentType, "json") || - strings.Contains(contentType, "javascript") || - strings.Contains(contentType, "urlencoded") || - strings.Contains(contentType, "utf") || - strings.Contains(contentType, "xml") { - - isText = true - } - - // only dump the whole body if this looks like text - response, err := httputil.DumpResponse(r, isText) - if err != nil { - return &rr, err - } - - rr.Response = string(response) - - bodyBytes, err := ioutil.ReadAll(r.Body) - if err != nil { - return &rr, err - } - rr.Body = bodyBytes - - // return an error if we got a non-200 status - if err == nil && rr.Status != RRStatusSuccess { - err = fmt.Errorf("received non 200 status: %d", rr.StatusCode) - } - - return &rr, err -} - // GetHTTPClient returns the shared HTTP client used by all Courier threads func GetHTTPClient() *http.Client { once.Do(func() { From 289278fe437aebad7c8a3442b9a50659a1d18aee Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 8 Aug 2022 15:25:54 -0500 Subject: [PATCH 052/294] Use NewChannelLogFromError where we have an error --- channel_log.go | 7 +------ handlers/freshchat/freshchat.go | 4 ++-- handlers/http.go | 2 +- handlers/telegram/telegram.go | 4 ++-- handlers/viber/viber.go | 5 ++--- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/channel_log.go b/channel_log.go index d29d977f0..77e17abfd 100644 --- a/channel_log.go +++ b/channel_log.go @@ -8,9 +8,6 @@ import ( "github.com/nyaruka/gocommon/httpx" ) -// NilStatusCode is used when we have an error before even sending anything -const NilStatusCode int = 417 - // NewChannelLog creates a new channel log for the passed in channel, id, and request and response info func NewChannelLog(description string, channel Channel, msgID MsgID, method string, url string, statusCode int, request string, response string, elapsed time.Duration, err error) *ChannelLog { @@ -74,7 +71,7 @@ func NewChannelLogFromTrace(description string, channel Channel, msgID MsgID, tr // NewChannelLogFromError creates a new channel log for the passed in channel, msg id and error func NewChannelLogFromError(description string, channel Channel, msgID MsgID, elapsed time.Duration, err error) *ChannelLog { - log := &ChannelLog{ + return &ChannelLog{ Description: description, Channel: channel, MsgID: msgID, @@ -82,8 +79,6 @@ func NewChannelLogFromError(description string, channel Channel, msgID MsgID, el CreatedOn: time.Now(), Elapsed: elapsed, } - - return log } // WithError augments the passed in ChannelLog with the passed in description and error if error is not nil diff --git a/handlers/freshchat/freshchat.go b/handlers/freshchat/freshchat.go index 86b26e55a..42f6ca588 100644 --- a/handlers/freshchat/freshchat.go +++ b/handlers/freshchat/freshchat.go @@ -148,8 +148,8 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat msgimage.Image = &Image{URL: mediaURL} payload.Messages[0].MessageParts = append(payload.Messages[0].MessageParts, *msgimage) default: - status.AddLog(courier.NewChannelLog("Unknown media type: "+mediaType, msg.Channel(), msg.ID(), "", "", courier.NilStatusCode, - "", "", time.Duration(0), fmt.Errorf("unknown media type: %s", mediaType))) + status.AddLog(courier.NewChannelLogFromError("Unknown media type: "+mediaType, msg.Channel(), msg.ID(), + time.Duration(0), fmt.Errorf("unknown media type: %s", mediaType))) } } diff --git a/handlers/http.go b/handlers/http.go index e0c8ed569..51ce91ec2 100644 --- a/handlers/http.go +++ b/handlers/http.go @@ -23,7 +23,7 @@ func MakeInsecureHTTPRequest(req *http.Request) (*httpx.Trace, error) { func MakeHTTPRequestWithClient(client *http.Client, req *http.Request) (*httpx.Trace, error) { trace, err := httpx.DoTrace(client, req, nil, nil, 0) if err != nil { - return nil, err + return trace, err } // return an error if we got a non-200 status diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index 20a3db45a..577f71ce1 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -321,8 +321,8 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat hasError = err != nil default: - status.AddLog(courier.NewChannelLog("Unknown attachment content type: "+attachment.ContentType, msg.Channel(), msg.ID(), "", "", courier.NilStatusCode, - "", "", time.Duration(0), fmt.Errorf("unknown attachment content type: %s", attachment.ContentType))) + status.AddLog(courier.NewChannelLogFromError("Unknown attachment content type: "+attachment.ContentType, + msg.Channel(), msg.ID(), time.Duration(0), fmt.Errorf("unknown attachment content type: %s", attachment.ContentType))) hasError = true } } diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index 1a4dc2c56..3631c0bd8 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -376,9 +376,8 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat msgText = "" default: - status.AddLog(courier.NewChannelLog("Unknown media type: "+mediaType, msg.Channel(), msg.ID(), "", "", courier.NilStatusCode, - "", "", time.Duration(0), fmt.Errorf("unknown media type: %s", mediaType))) - + status.AddLog(courier.NewChannelLogFromError("Unknown media type: "+mediaType, msg.Channel(), msg.ID(), + time.Duration(0), fmt.Errorf("unknown media type: %s", mediaType))) } } else { From 761bf41b9db43cce79a77dae686ad9d30b21c6d3 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 9 Aug 2022 15:28:18 -0500 Subject: [PATCH 053/294] Update CHANGELOG.md for v7.5.7 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8441b6c1..4f749449a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.7 +---------- + * Convert remaining channel types to use httpx.Trace + v7.5.6 ---------- * Fix URLs from non-resolved attachments that may not be properly escaped From 1767076bd8b3b0abf081f30d04447b9c4007bb59 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 9 Aug 2022 12:10:02 -0500 Subject: [PATCH 054/294] Rework handler sending to record logs via a logger rather than on the status object --- channel_log.go | 51 ++++++++++++++++++++++ handler.go | 2 +- handler_test.go | 8 ++-- handlers/africastalking/africastalking.go | 18 ++++---- handlers/arabiacell/arabiacell.go | 18 +++----- handlers/blackmyna/blackmyna.go | 16 +++---- handlers/bongolive/bongolive.go | 16 +++---- handlers/burstsms/burstsms.go | 18 +++----- handlers/chikka/chikka.go | 19 ++++----- handlers/clickatell/clickatell.go | 16 +++---- handlers/clickmobile/clickmobile.go | 15 +++---- handlers/clicksend/clicksend.go | 18 ++++---- handlers/dart/dart.go | 16 +++---- handlers/discord/discord.go | 13 +++--- handlers/dmark/dmark.go | 16 +++---- handlers/external/external.go | 16 +++---- handlers/facebook/facebook.go | 2 +- handlers/facebookapp/facebookapp.go | 2 +- handlers/firebase/firebase.go | 18 ++++---- handlers/freshchat/freshchat.go | 13 +++--- handlers/globe/globe.go | 11 +++-- handlers/highconnection/highconnection.go | 12 ++---- handlers/hormuud/hormuud.go | 52 +++++++++-------------- handlers/http.go | 30 +++++++++++++ handlers/http_test.go | 42 ++++++++++++++++++ handlers/i2sms/i2sms.go | 18 +++----- handlers/infobip/infobip.go | 20 ++++----- handlers/jasmin/jasmin.go | 18 ++++---- handlers/jiochat/jiochat.go | 4 +- handlers/junebug/junebug.go | 14 +++--- handlers/kaleyra/kaleyra.go | 4 +- handlers/kannel/kannel.go | 4 +- handlers/line/line.go | 4 +- handlers/m3tech/m3tech.go | 9 ++-- handlers/macrokiosk/macrokiosk.go | 12 +++--- handlers/mblox/mblox.go | 12 +++--- handlers/messangi/messangi.go | 18 +++----- handlers/mtarget/mtarget.go | 19 ++++----- handlers/nexmo/nexmo.go | 4 +- handlers/novo/novo.go | 16 +++---- handlers/playmobile/playmobile.go | 19 +++------ handlers/plivo/plivo.go | 4 +- handlers/redrabbit/redrabbit.go | 9 ++-- handlers/rocketchat/rocketchat.go | 2 +- handlers/shaqodoon/shaqodoon.go | 15 ++++--- handlers/slack/slack.go | 2 +- handlers/smscentral/smscentral.go | 19 +++------ handlers/start/start.go | 2 +- handlers/telegram/telegram.go | 4 +- handlers/telesom/telesom.go | 4 +- handlers/test.go | 4 +- handlers/thinq/thinq.go | 4 +- handlers/twiml/twiml.go | 4 +- handlers/twitter/twitter.go | 2 +- handlers/viber/viber.go | 4 +- handlers/vk/vk.go | 2 +- handlers/vk/vk_test.go | 2 +- handlers/wavy/wavy.go | 13 +++--- handlers/wechat/wechat.go | 4 +- handlers/whatsapp/whatsapp.go | 4 +- handlers/yo/yo.go | 15 +++---- handlers/zenvia/zenvia.go | 16 +++---- handlers/zenviaold/zenviaold.go | 16 +++---- sender.go | 17 ++++++-- server.go | 6 +-- 65 files changed, 418 insertions(+), 409 deletions(-) diff --git a/channel_log.go b/channel_log.go index 77e17abfd..7ccf345c2 100644 --- a/channel_log.go +++ b/channel_log.go @@ -111,3 +111,54 @@ type ChannelLog struct { Elapsed time.Duration CreatedOn time.Time } + +// ChannelLogType is the type of channel interaction we are logging +type ChannelLogType string + +const ( + ChannelLogTypeSend ChannelLogType = "send" +) + +var logTypeDescriptions = map[ChannelLogType]string{ + ChannelLogTypeSend: "Message Send", +} +var logTypeErrorDescriptions = map[ChannelLogType]string{ + ChannelLogTypeSend: "Message Send Error", +} + +type ChannelLogger struct { + type_ ChannelLogType + msg Msg + + logs []*ChannelLog +} + +func NewChannelLoggerForSend(msg Msg) *ChannelLogger { + return &ChannelLogger{type_: ChannelLogTypeSend, msg: msg} +} + +// HTTP logs an HTTP request and response +func (l *ChannelLogger) HTTP(t *httpx.Trace) { + var description string + if t.Response == nil || t.Response.StatusCode/100 != 2 { + description = logTypeErrorDescriptions[l.type_] + } else { + description = logTypeDescriptions[l.type_] + } + + l.logs = append(l.logs, NewChannelLogFromTrace(description, l.msg.Channel(), l.msg.ID(), t)) +} + +func (l *ChannelLogger) Error(err error) { + // if we have an existing log which isn't already an error, update it + if len(l.logs) > 0 && l.logs[len(l.logs)-1].Error == "" { + l.logs[len(l.logs)-1].Error = err.Error() + l.logs[len(l.logs)-1].Description = logTypeErrorDescriptions[l.type_] + } else { + l.logs = append(l.logs, NewChannelLogFromError(logTypeErrorDescriptions[l.type_], l.msg.Channel(), l.msg.ID(), 0, err)) + } +} + +func (l *ChannelLogger) Logs() []*ChannelLog { + return l.logs +} diff --git a/handler.go b/handler.go index 9458c07f1..f34b23e09 100644 --- a/handler.go +++ b/handler.go @@ -25,7 +25,7 @@ type ChannelHandler interface { ChannelName() string UseChannelRouteUUID() bool GetChannel(context.Context, *http.Request) (Channel, error) - SendMsg(context.Context, Msg) (MsgStatus, error) + Send(context.Context, Msg, *ChannelLogger) (MsgStatus, error) } // URNDescriber is the interface handlers which can look up URN metadata for new contacts should satisfy. diff --git a/handler_test.go b/handler_test.go index 6b802ad92..bcd9a96ba 100644 --- a/handler_test.go +++ b/handler_test.go @@ -43,8 +43,8 @@ func (h *dummyHandler) Initialize(s Server) error { return nil } -// SendMsg sends the passed in message, returning any error -func (h *dummyHandler) SendMsg(ctx context.Context, msg Msg) (MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *dummyHandler) Send(ctx context.Context, msg Msg, logger *ChannelLogger) (MsgStatus, error) { return h.backend.NewMsgStatusForID(msg.Channel(), msg.ID(), MsgSent), nil } @@ -101,11 +101,11 @@ func TestHandling(t *testing.T) { // sleep a second, sender should take care of it in that time time.Sleep(time.Second) - // message should have errored because we have registered handlers + // message should have errored because we don't have a registered handler assert.Equal(1, len(mb.msgStatuses)) assert.Equal(msg.ID(), mb.msgStatuses[0].ID()) assert.Equal(MsgErrored, mb.msgStatuses[0].Status()) - assert.Equal(1, len(mb.msgStatuses[0].Logs())) + assert.Equal(1, len(mb.channelLogs)) // clear our statuses mb.msgStatuses = nil diff --git a/handlers/africastalking/africastalking.go b/handlers/africastalking/africastalking.go index d7205a49c..cec24a32e 100644 --- a/handlers/africastalking/africastalking.go +++ b/handlers/africastalking/africastalking.go @@ -113,8 +113,8 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { isSharedStr := msg.Channel().ConfigForKey(configIsShared, false) isShared, _ := isSharedStr.(bool) @@ -128,6 +128,8 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus return nil, fmt.Errorf("no API key set for AT channel") } + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + // build our request form := url.Values{ "username": []string{username}, @@ -148,24 +150,20 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus req.Header.Set("Accept", "application/json") req.Header.Set("apikey", apiKey) - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } // was this request successful? - msgStatus, _ := jsonparser.GetString(trace.ResponseBody, "SMSMessageData", "Recipients", "[0]", "status") + msgStatus, _ := jsonparser.GetString(respBody, "SMSMessageData", "Recipients", "[0]", "status") if msgStatus != "Success" { status.SetStatus(courier.MsgErrored) return status, nil } // grab the external id if we can - externalID, _ := jsonparser.GetString(trace.ResponseBody, "SMSMessageData", "Recipients", "[0]", "messageId") + externalID, _ := jsonparser.GetString(respBody, "SMSMessageData", "Recipients", "[0]", "messageId") status.SetStatus(courier.MsgWired) status.SetExternalID(externalID) diff --git a/handlers/arabiacell/arabiacell.go b/handlers/arabiacell/arabiacell.go index 26301b4f9..6e627d897 100644 --- a/handlers/arabiacell/arabiacell.go +++ b/handlers/arabiacell/arabiacell.go @@ -53,8 +53,8 @@ type mtResponse struct { MessageID string `xml:"message_id"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for AC channel") @@ -94,20 +94,16 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/xml") - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } // parse our response as XML response := &mtResponse{} - err = xml.Unmarshal(trace.ResponseBody, response) + err = xml.Unmarshal(respBody, response) if err != nil { - log.WithError("Message Send Error", err) + logger.Error(err) break } @@ -117,7 +113,7 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus status.SetExternalID(response.MessageID) } else { status.SetStatus(courier.MsgFailed) - log.WithError("Message Send Error", fmt.Errorf("Received invalid response code: %s", response.Code)) + logger.Error(fmt.Errorf("Received invalid response code: %s", response.Code)) break } } diff --git a/handlers/blackmyna/blackmyna.go b/handlers/blackmyna/blackmyna.go index 269c17f6f..3f3a220c1 100644 --- a/handlers/blackmyna/blackmyna.go +++ b/handlers/blackmyna/blackmyna.go @@ -94,8 +94,8 @@ func (h *handler) StatusMessage(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for BM channel") @@ -111,6 +111,8 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat return nil, fmt.Errorf("no API key set for BM channel") } + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + // build our request form := url.Values{ "address": []string{msg.URN().Path()}, @@ -126,17 +128,13 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.SetBasicAuth(username, password) - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } // get our external id - externalID, _ := jsonparser.GetString(trace.ResponseBody, "[0]", "id") + externalID, _ := jsonparser.GetString(respBody, "[0]", "id") if externalID == "" { return status, errors.Errorf("no external id returned in body") } diff --git a/handlers/bongolive/bongolive.go b/handlers/bongolive/bongolive.go index 323827df2..1bcf5630b 100644 --- a/handlers/bongolive/bongolive.go +++ b/handlers/bongolive/bongolive.go @@ -123,8 +123,8 @@ func writeBongoLiveResponse(w http.ResponseWriter) error { } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for %s channel", msg.Channel().ChannelType()) @@ -163,23 +163,19 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - trace, err := handlers.MakeInsecureHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTPInsecure(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } // was this request successful? - msgStatus, _ := jsonparser.GetString(trace.ResponseBody, "results", "[0]", "status") + msgStatus, _ := jsonparser.GetString(respBody, "results", "[0]", "status") if msgStatus != "0" { status.SetStatus(courier.MsgErrored) return status, nil } // grab the external id if we can - externalID, _ := jsonparser.GetString(trace.ResponseBody, "results", "[0]", "msgid") + externalID, _ := jsonparser.GetString(respBody, "results", "[0]", "msgid") status.SetStatus(courier.MsgWired) status.SetExternalID(externalID) diff --git a/handlers/burstsms/burstsms.go b/handlers/burstsms/burstsms.go index 96c9ea460..6366a97f0 100644 --- a/handlers/burstsms/burstsms.go +++ b/handlers/burstsms/burstsms.go @@ -55,8 +55,8 @@ type mtResponse struct { MessageID int64 `json:"message_id"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for BS channel") @@ -83,20 +83,16 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } // parse our response as json response := &mtResponse{} - err = json.Unmarshal(trace.ResponseBody, response) + err = json.Unmarshal(respBody, response) if err != nil { - log.WithError("Message Send Error", err) + logger.Error(err) break } @@ -105,7 +101,7 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus status.SetExternalID(fmt.Sprintf("%d", response.MessageID)) } else { status.SetStatus(courier.MsgFailed) - log.WithError("Message Send Error", fmt.Errorf("Received invalid message id: %d", response.MessageID)) + logger.Error(fmt.Errorf("Received invalid message id: %d", response.MessageID)) break } } diff --git a/handlers/chikka/chikka.go b/handlers/chikka/chikka.go index 6d94b6c8d..a76749a4e 100644 --- a/handlers/chikka/chikka.go +++ b/handlers/chikka/chikka.go @@ -103,8 +103,8 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for CK channel") @@ -140,11 +140,11 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - trace, err := handlers.MakeHTTPRequest(req) + resp, respBody, err := handlers.RequestHTTP(req, logger) - if trace.Response != nil && trace.Response.StatusCode == 400 { - message, _ := jsonparser.GetString(trace.ResponseBody, "message") - description, _ := jsonparser.GetString(trace.ResponseBody, "description") + if resp != nil && resp.StatusCode == 400 { + message, _ := jsonparser.GetString(respBody, "message") + description, _ := jsonparser.GetString(respBody, "description") if message == "BAD REQUEST" && description == `Invalid\/Used Request ID` { delete(form, "request_id") @@ -153,18 +153,15 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req, _ = http.NewRequest(http.MethodPost, sendURL, strings.NewReader(form.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - trace, err = handlers.MakeHTTPRequest(req) + resp, _, err = handlers.RequestHTTP(req, logger) } } - // record our status and log - status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) - if err != nil { + if err != nil || resp.StatusCode/100 != 2 { return status, nil } status.SetStatus(courier.MsgWired) - } return status, nil diff --git a/handlers/clickatell/clickatell.go b/handlers/clickatell/clickatell.go index 171618cac..5a49cbc79 100644 --- a/handlers/clickatell/clickatell.go +++ b/handlers/clickatell/clickatell.go @@ -168,8 +168,8 @@ func decodeUTF16BE(b []byte) (string, error) { return ret.String(), nil } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { apiKey := msg.Channel().StringConfigForKey(courier.ConfigAPIKey, "") if apiKey == "" { return nil, fmt.Errorf("no api_key set for CT channel") @@ -195,19 +195,15 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } // try to read out our message id, if we can't then this was a failure - externalID, err := jsonparser.GetString(trace.ResponseBody, "messages", "[0]", "apiMessageId") + externalID, err := jsonparser.GetString(respBody, "messages", "[0]", "apiMessageId") if err != nil { - log.WithError("Send Error", err) + logger.Error(err) } else { status.SetStatus(courier.MsgWired) status.SetExternalID(externalID) diff --git a/handlers/clickmobile/clickmobile.go b/handlers/clickmobile/clickmobile.go index 57fbfd571..367d15557 100644 --- a/handlers/clickmobile/clickmobile.go +++ b/handlers/clickmobile/clickmobile.go @@ -97,8 +97,8 @@ type mtPayload struct { Message string `json:"message"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for CM channel") @@ -156,19 +156,16 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequest(req) - - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - responseCode, err := jsonparser.GetString(trace.ResponseBody, "code") + responseCode, err := jsonparser.GetString(respBody, "code") if responseCode == "000" { status.SetStatus(courier.MsgWired) } else { - log.WithError("Message Send Error", fmt.Errorf("Received invalid response content: %s", string(trace.ResponseBody))) + logger.Error(fmt.Errorf("Received invalid response content: %s", string(respBody))) } } return status, nil diff --git a/handlers/clicksend/clicksend.go b/handlers/clicksend/clicksend.go index cdfeadd10..f49391a9e 100644 --- a/handlers/clicksend/clicksend.go +++ b/handlers/clicksend/clicksend.go @@ -60,8 +60,8 @@ type mtPayload struct { } `json:"messages"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("Missing 'username' config for CS channel") @@ -93,24 +93,22 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.SetBasicAuth(username, password) - trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } // first read our status - s, err := jsonparser.GetString(trace.ResponseBody, "data", "messages", "[0]", "status") + s, err := jsonparser.GetString(respBody, "data", "messages", "[0]", "status") if s != "SUCCESS" { - log.WithError("Message Send Error", errors.Errorf("received non SUCCESS status: %s", s)) + logger.Error(errors.Errorf("received non SUCCESS status: %s", s)) return status, nil } // then get our external id - id, err := jsonparser.GetString(trace.ResponseBody, "data", "messages", "[0]", "message_id") + id, err := jsonparser.GetString(respBody, "data", "messages", "[0]", "message_id") if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to get message_id for message")) + logger.Error(errors.Errorf("unable to get message_id for message")) return status, nil } diff --git a/handlers/dart/dart.go b/handlers/dart/dart.go index 29b76a3b0..69ba48e29 100644 --- a/handlers/dart/dart.go +++ b/handlers/dart/dart.go @@ -138,8 +138,8 @@ func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWr return err } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for %s channel", msg.Channel().ChannelType()) @@ -179,16 +179,12 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - responseText := string(trace.ResponseBody) + responseText := string(respBody) if responseText != "000" { errorMessage := "Unknown error" if responseText == "001" { @@ -197,7 +193,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat if responseText == "101" { errorMessage = "Error 101: Account expired or invalid parameters" } - log.WithError("Send Error", fmt.Errorf(errorMessage)) + logger.Error(fmt.Errorf(errorMessage)) return status, nil } diff --git a/handlers/discord/discord.go b/handlers/discord/discord.go index bb60f9d00..7f6d3f4c6 100644 --- a/handlers/discord/discord.go +++ b/handlers/discord/discord.go @@ -153,8 +153,8 @@ func (h *handler) receiveStatus(ctx context.Context, statusString string, channe return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { sendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, "") if sendURL == "" { return nil, fmt.Errorf("no send url set for DS channel") @@ -208,14 +208,11 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Authorization", authorization) } - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, _, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } + // If we don't have an error, set the message as wired and move on status.SetStatus(courier.MsgWired) diff --git a/handlers/dmark/dmark.go b/handlers/dmark/dmark.go index 2244d4bd4..cfb8ea6a6 100644 --- a/handlers/dmark/dmark.go +++ b/handlers/dmark/dmark.go @@ -106,8 +106,8 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { // get our authentication token auth := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if auth == "" { @@ -135,19 +135,15 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Token %s", auth)) - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } // grab the external id - externalID, err := jsonparser.GetString(trace.ResponseBody, "sms_id") + externalID, err := jsonparser.GetString(respBody, "sms_id") if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to get sms_id from body")) + logger.Error(errors.Errorf("unable to get sms_id from body")) return status, nil } diff --git a/handlers/external/external.go b/handlers/external/external.go index e118ca7a5..326344ec4 100644 --- a/handlers/external/external.go +++ b/handlers/external/external.go @@ -272,8 +272,8 @@ func (h *handler) receiveStatus(ctx context.Context, statusString string, channe return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { sendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, "") if sendURL == "" { return nil, fmt.Errorf("no send url set for EX channel") @@ -363,19 +363,15 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set(hKey, fmt.Sprint(hValue)) } - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - if responseContent == "" || strings.Contains(string(trace.ResponseBody), responseContent) { + if responseContent == "" || strings.Contains(string(respBody), responseContent) { status.SetStatus(courier.MsgWired) } else { - log.WithError("Message Send Error", fmt.Errorf("Received invalid response content: %s", string(trace.ResponseBody))) + logger.Error(fmt.Errorf("Received invalid response content: %s", string(respBody))) } } diff --git a/handlers/facebook/facebook.go b/handlers/facebook/facebook.go index 44c33d02c..519e4fab5 100644 --- a/handlers/facebook/facebook.go +++ b/handlers/facebook/facebook.go @@ -471,7 +471,7 @@ type mtQuickReply struct { ContentType string `json:"content_type"` } -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { // can't do anything without an access token accessToken := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if accessToken == "" { diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index ceec98826..5043e63d2 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -803,7 +803,7 @@ type mtQuickReply struct { ContentType string `json:"content_type"` } -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { if msg.Channel().ChannelType() == "FBA" || msg.Channel().ChannelType() == "IG" { return h.sendFacebookInstagramMsg(ctx, msg) } else if msg.Channel().ChannelType() == "WAC" { diff --git a/handlers/firebase/firebase.go b/handlers/firebase/firebase.go index 421549d92..a86454b8d 100644 --- a/handlers/firebase/firebase.go +++ b/handlers/firebase/firebase.go @@ -134,8 +134,8 @@ type mtNotification struct { Body string `json:"body"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { title := msg.Channel().StringConfigForKey(configTitle, "") if title == "" { return nil, fmt.Errorf("no FCM_TITLE set for FCM channel") @@ -194,25 +194,23 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("key=%s", fcmKey)) - trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } // was this successful - success, _ := jsonparser.GetInt(trace.ResponseBody, "success") + success, _ := jsonparser.GetInt(respBody, "success") if success != 1 { - log.WithError("Message Send Error", errors.Errorf("received non-1 value for success in response")) + logger.Error(errors.Errorf("received non-1 value for success in response")) return status, nil } // grab the id if this is our first part if i == 0 { - externalID, err := jsonparser.GetInt(trace.ResponseBody, "multicast_id") + externalID, err := jsonparser.GetInt(respBody, "multicast_id") if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to get multicast_id from response")) + logger.Error(errors.Errorf("unable to get multicast_id from response")) return status, nil } status.SetExternalID(fmt.Sprintf("%d", externalID)) diff --git a/handlers/freshchat/freshchat.go b/handlers/freshchat/freshchat.go index 42f6ca588..2e8a8a807 100644 --- a/handlers/freshchat/freshchat.go +++ b/handlers/freshchat/freshchat.go @@ -101,7 +101,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) } -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { agentID := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if agentID == "" { @@ -168,14 +168,11 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat var bearer = "Bearer " + authToken req.Header.Set("Authorization", bearer) - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { - return status, err + resp, _, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return status, nil } + status.SetStatus(courier.MsgWired) return status, nil diff --git a/handlers/globe/globe.go b/handlers/globe/globe.go index 36b7ee84d..823cfec97 100644 --- a/handlers/globe/globe.go +++ b/handlers/globe/globe.go @@ -125,8 +125,8 @@ type mtPayload struct { AppSecret string `json:"app_secret"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { appID := msg.Channel().StringConfigForKey(configAppID, "") if appID == "" { return nil, fmt.Errorf("Missing 'app_id' config for GL channel") @@ -163,12 +163,11 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, _, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } + status.SetStatus(courier.MsgWired) } diff --git a/handlers/highconnection/highconnection.go b/handlers/highconnection/highconnection.go index ba76ec5ec..63aae3dc1 100644 --- a/handlers/highconnection/highconnection.go +++ b/handlers/highconnection/highconnection.go @@ -115,8 +115,8 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for HX channel") @@ -151,16 +151,12 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat msgURL.RawQuery = form.Encode() req, err := http.NewRequest(http.MethodPost, msgURL.String(), nil) - if err != nil { return nil, err } - trace, err := handlers.MakeHTTPRequest(req) - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, _, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/hormuud/hormuud.go b/handlers/hormuud/hormuud.go index 67948cf64..7bbc2d47d 100644 --- a/handlers/hormuud/hormuud.go +++ b/handlers/hormuud/hormuud.go @@ -14,7 +14,6 @@ import ( "github.com/gomodule/redigo/redis" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/gocommon/httpx" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -80,24 +79,13 @@ type mtPayload struct { UDH string `json:"UDH"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - token, trace, err := h.FetchToken(ctx, msg.Channel(), msg) - if trace == nil && err != nil { - return nil, errors.Wrapf(err, "unable to fetch token") - } - - // if we made a request for our token, stash that in our status - if trace != nil { - log := courier.NewChannelLogFromTrace("Token Retrieved", msg.Channel(), msg.ID(), trace).WithError("Token Retrieval Error", err) - status.AddLog(log) - } - - // failed getting a token? we are done + token, err := h.FetchToken(ctx, msg.Channel(), msg, logger) if err != nil { - return status, nil + return status, errors.Wrapf(err, "unable to fetch token") } parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) @@ -123,16 +111,15 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) - trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } + status.SetStatus(courier.MsgWired) // try to get the message id out - id, _ := jsonparser.GetString(trace.ResponseBody, "Data", "MessageID") + id, _ := jsonparser.GetString(respBody, "Data", "MessageID") if id != "" && i == 0 { status.SetExternalID(id) } @@ -146,7 +133,7 @@ type tokenResponse struct { } // FetchToken gets the current token for this channel, either from Redis if cached or by requesting it -func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg courier.Msg) (string, *httpx.Trace, error) { +func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg courier.Msg, logger *courier.ChannelLogger) (string, error) { // first check whether we have it in redis conn := h.Backend().RedisPool().Get() token, err := redis.String(conn.Do("GET", fmt.Sprintf("hm_token_%s", channel.UUID()))) @@ -154,18 +141,18 @@ func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg c // got a token, use it if token != "" { - return token, nil, nil + return token, nil } // no token, lets go fetch one username := channel.StringConfigForKey(courier.ConfigUsername, "") if username == "" { - return "", nil, fmt.Errorf("Missing 'username' config for HM channel") + return "", fmt.Errorf("Missing 'username' config for HM channel") } password := channel.StringConfigForKey(courier.ConfigPassword, "") if password == "" { - return "", nil, fmt.Errorf("Missing 'password' config for HM channel") + return "", fmt.Errorf("Missing 'password' config for HM channel") } form := url.Values{ @@ -179,18 +166,17 @@ func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg c req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - return "", trace, errors.Wrapf(err, "error making token request") + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return "", errors.Wrapf(err, "error making token request") } - token, err = jsonparser.GetString(trace.ResponseBody, "access_token") + token, err = jsonparser.GetString(respBody, "access_token") if err != nil { - return "", trace, errors.Wrapf(err, "error getting access_token from response") + return "", errors.Wrapf(err, "error getting access_token from response") } - if token == "" { - return "", trace, errors.Errorf("no access token returned") + return "", errors.Errorf("no access token returned") } // we got a token, cache it to redis with a 90 minute expiration @@ -202,5 +188,5 @@ func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg c logrus.WithError(err).Error("error caching HM access token") } - return token, trace, nil + return token, nil } diff --git a/handlers/http.go b/handlers/http.go index 51ce91ec2..6a46a6b65 100644 --- a/handlers/http.go +++ b/handlers/http.go @@ -4,10 +4,40 @@ import ( "fmt" "net/http" + "github.com/nyaruka/courier" "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/httpx" ) +// RequestHTTP does the given request, logging the trace, and returns the response +func RequestHTTP(req *http.Request, logger *courier.ChannelLogger) (*http.Response, []byte, error) { + return RequestHTTPWithClient(utils.GetHTTPClient(), req, logger) +} + +// RequestHTTPInsecure does the given request using an insecure client that does not validate SSL certificates, +// logging the trace, and returns the response +func RequestHTTPInsecure(req *http.Request, logger *courier.ChannelLogger) (*http.Response, []byte, error) { + return RequestHTTPWithClient(utils.GetInsecureHTTPClient(), req, logger) +} + +// RequestHTTP does the given request using the given client, logging the trace, and returns the response +func RequestHTTPWithClient(client *http.Client, req *http.Request, logger *courier.ChannelLogger) (*http.Response, []byte, error) { + var resp *http.Response + var body []byte + + trace, err := httpx.DoTrace(client, req, nil, nil, 0) + if trace != nil { + logger.HTTP(trace) + resp = trace.Response + body = trace.ResponseBody + } + if err != nil { + return nil, nil, err + } + + return resp, body, nil +} + // MakeHTTPRequest makes the given request and returns the trace func MakeHTTPRequest(req *http.Request) (*httpx.Trace, error) { return MakeHTTPRequestWithClient(utils.GetHTTPClient(), req) diff --git a/handlers/http_test.go b/handlers/http_test.go index 437a57967..80c4123c8 100644 --- a/handlers/http_test.go +++ b/handlers/http_test.go @@ -4,11 +4,53 @@ import ( "net/http" "testing" + "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/gocommon/httpx" + "github.com/nyaruka/gocommon/urns" "github.com/stretchr/testify/assert" ) +func TestDoHTTPRequest(t *testing.T) { + httpx.SetRequestor(httpx.NewMockRequestor(map[string][]httpx.MockResponse{ + "https://api.messages.com/send.json": { + httpx.NewMockResponse(200, nil, []byte(`{"status":"success"}`)), + httpx.NewMockResponse(400, nil, []byte(`{"status":"error"}`)), + }, + })) + defer httpx.SetRequestor(httpx.DefaultRequestor) + + mb := courier.NewMockBackend() + mc := courier.NewMockChannel("7a8ff1d4-f211-4492-9d05-e1905f6da8c8", "NX", "1234", "EC", nil) + mm := mb.NewOutgoingMsg(mc, courier.NewMsgID(123), urns.URN("tel:+1234"), "Hello World", false, nil, "", "") + logger := courier.NewChannelLoggerForSend(mm) + + req, _ := http.NewRequest("POST", "https://api.messages.com/send.json", nil) + resp, respBody, err := handlers.RequestHTTP(req, logger) + assert.NoError(t, err) + assert.Equal(t, 200, resp.StatusCode) + assert.Equal(t, []byte(`{"status":"success"}`), respBody) + assert.Len(t, logger.Logs(), 1) + + log1 := logger.Logs()[0] + assert.Equal(t, 200, log1.StatusCode) + assert.Equal(t, mc, log1.Channel) + assert.Equal(t, courier.NewMsgID(123), log1.MsgID) + assert.Equal(t, "https://api.messages.com/send.json", log1.URL) + + req, _ = http.NewRequest("POST", "https://api.messages.com/send.json", nil) + resp, respBody, err = handlers.RequestHTTP(req, logger) + assert.NoError(t, err) + assert.Equal(t, 400, resp.StatusCode) + assert.Len(t, logger.Logs(), 2) + + log2 := logger.Logs()[1] + assert.Equal(t, 400, log2.StatusCode) + assert.Equal(t, mc, log2.Channel) + assert.Equal(t, courier.NewMsgID(123), log2.MsgID) + assert.Equal(t, "https://api.messages.com/send.json", log2.URL) +} + func TestMakeHTTPRequest(t *testing.T) { httpx.SetRequestor(httpx.NewMockRequestor(map[string][]httpx.MockResponse{ "https://api.messages.com/send.json": { diff --git a/handlers/i2sms/i2sms.go b/handlers/i2sms/i2sms.go index 51474bb5e..3aa454ff3 100644 --- a/handlers/i2sms/i2sms.go +++ b/handlers/i2sms/i2sms.go @@ -82,8 +82,8 @@ type mtResponse struct { ErrorCode string `json:"error_code"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for I2 channel") @@ -116,20 +116,16 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } // parse our response as JSON response := &mtResponse{} - err = json.Unmarshal(trace.ResponseBody, response) + err = json.Unmarshal(respBody, response) if err != nil { - log.WithError("Message Send Error", err) + logger.Error(err) break } @@ -139,7 +135,7 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus status.SetExternalID(response.Result.SessionID) } else { status.SetStatus(courier.MsgFailed) - log.WithError("Message Send Error", fmt.Errorf("Received invalid response code: %s", response.ErrorCode)) + logger.Error(fmt.Errorf("Received invalid response code: %s", response.ErrorCode)) break } } diff --git a/handlers/infobip/infobip.go b/handlers/infobip/infobip.go index e165383bb..118f3d6cc 100644 --- a/handlers/infobip/infobip.go +++ b/handlers/infobip/infobip.go @@ -174,8 +174,8 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgsAndResponse(ctx, h, msgs, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for IB channel") @@ -225,24 +225,20 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.SetBasicAuth(username, password) - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace) - status.AddLog(log) - if err != nil { - log.WithError("Message Send Error", err) + + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - groupID, err := jsonparser.GetInt(trace.ResponseBody, "messages", "[0]", "status", "groupId") + groupID, err := jsonparser.GetInt(respBody, "messages", "[0]", "status", "groupId") if err != nil || (groupID != 1 && groupID != 3) { - log.WithError("Message Send Error", errors.Errorf("received error status: '%d'", groupID)) + logger.Error(errors.Errorf("received error status: '%d'", groupID)) return status, nil } - externalID, err := jsonparser.GetString(trace.ResponseBody, "messages", "[0]", "messageId") + externalID, err := jsonparser.GetString(respBody, "messages", "[0]", "messageId") if externalID != "" { status.SetExternalID(externalID) } diff --git a/handlers/jasmin/jasmin.go b/handlers/jasmin/jasmin.go index b0e6ad163..299a7de53 100644 --- a/handlers/jasmin/jasmin.go +++ b/handlers/jasmin/jasmin.go @@ -118,8 +118,8 @@ func writeJasminACK(w http.ResponseWriter) error { return err } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for JS channel") @@ -160,17 +160,17 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat return nil, err } - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) - if err == nil { - status.SetStatus(courier.MsgWired) + + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return status, nil } + status.SetStatus(courier.MsgWired) + // try to read our external id out - matches := idRegex.FindSubmatch(trace.ResponseBody) + matches := idRegex.FindSubmatch(respBody) if len(matches) == 2 { status.SetExternalID(string(matches[1])) } diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 991d38fa0..4b46106df 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -239,8 +239,8 @@ type mtPayload struct { } `json:"text"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { accessToken, err := h.getAccessToken(msg.Channel()) if err != nil { return nil, err diff --git a/handlers/junebug/junebug.go b/handlers/junebug/junebug.go index eaf532066..0afb6b168 100644 --- a/handlers/junebug/junebug.go +++ b/handlers/junebug/junebug.go @@ -154,7 +154,7 @@ type mtPayload struct { EventAuthToken string `json:"event_auth_token,omitempty"` } -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { sendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, "") if sendURL == "" { return nil, fmt.Errorf("No send_url set for JN channel") @@ -197,18 +197,14 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.SetBasicAuth(username, password) - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - externalID, err := jsonparser.GetString(trace.ResponseBody, "result", "message_id") + externalID, err := jsonparser.GetString(respBody, "result", "message_id") if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to get result.message_id from body")) + logger.Error(errors.Errorf("unable to get result.message_id from body")) return status, nil } diff --git a/handlers/kaleyra/kaleyra.go b/handlers/kaleyra/kaleyra.go index d12815281..be276ee14 100644 --- a/handlers/kaleyra/kaleyra.go +++ b/handlers/kaleyra/kaleyra.go @@ -137,8 +137,8 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { start := time.Now() accountSID := msg.Channel().StringConfigForKey(configAccountSID, "") apiKey := msg.Channel().StringConfigForKey(configApiKey, "") diff --git a/handlers/kannel/kannel.go b/handlers/kannel/kannel.go index 64b9605f8..690d2a07d 100644 --- a/handlers/kannel/kannel.go +++ b/handlers/kannel/kannel.go @@ -119,8 +119,8 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for KN channel") diff --git a/handlers/line/line.go b/handlers/line/line.go index b2df2610b..ba375f481 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -264,8 +264,8 @@ type mtPayload struct { Messages json.RawMessage `json:"messages"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { authToken := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if authToken == "" { return nil, fmt.Errorf("no auth token set for LN channel: %s", msg.Channel().UUID()) diff --git a/handlers/m3tech/m3tech.go b/handlers/m3tech/m3tech.go index 3c18e9a49..b6ee072f5 100644 --- a/handlers/m3tech/m3tech.go +++ b/handlers/m3tech/m3tech.go @@ -68,8 +68,8 @@ func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWr return err } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for M3 channel") @@ -113,9 +113,8 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat return nil, err } - trace, err := handlers.MakeHTTPRequest(req) - status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) - if err != nil { + resp, _, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { break } diff --git a/handlers/macrokiosk/macrokiosk.go b/handlers/macrokiosk/macrokiosk.go index b7127e71f..045785990 100644 --- a/handlers/macrokiosk/macrokiosk.go +++ b/handlers/macrokiosk/macrokiosk.go @@ -151,8 +151,8 @@ type mtPayload struct { Type string `json:"type"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") password := msg.Channel().StringConfigForKey(courier.ConfigPassword, "") servID := msg.Channel().StringConfigForKey(configMacrokioskServiceID, "") @@ -191,14 +191,12 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - externalID, err := jsonparser.GetString(trace.ResponseBody, "MsgID") + externalID, err := jsonparser.GetString(respBody, "MsgID") if err != nil { return status, fmt.Errorf("unable to parse response body from Macrokiosk") } diff --git a/handlers/mblox/mblox.go b/handlers/mblox/mblox.go index 74bdd7882..70ed01cf3 100644 --- a/handlers/mblox/mblox.go +++ b/handlers/mblox/mblox.go @@ -114,8 +114,8 @@ type mtPayload struct { DeliveryReport string `json:"delivery_report"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") password := msg.Channel().StringConfigForKey(courier.ConfigPassword, "") if username == "" || password == "" { @@ -143,14 +143,12 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", password)) - trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - externalID, err := jsonparser.GetString(trace.ResponseBody, "id") + externalID, err := jsonparser.GetString(respBody, "id") if err != nil { return status, fmt.Errorf("unable to parse response body from MBlox") } diff --git a/handlers/messangi/messangi.go b/handlers/messangi/messangi.go index 88c213afb..3394b291e 100644 --- a/handlers/messangi/messangi.go +++ b/handlers/messangi/messangi.go @@ -57,8 +57,8 @@ type mtResponse struct { Description string `xml:"description"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { publicKey := msg.Channel().StringConfigForKey(configPublicKey, "") if publicKey == "" { return nil, fmt.Errorf("no public_key set for MG channel") @@ -94,20 +94,16 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat return nil, err } - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } // parse our response as XML response := &mtResponse{} - err = xml.Unmarshal(trace.ResponseBody, response) + err = xml.Unmarshal(respBody, response) if err != nil { - log.WithError("Message Send Error", err) + logger.Error(err) break } @@ -116,7 +112,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat status.SetStatus(courier.MsgWired) } else { status.SetStatus(courier.MsgFailed) - log.WithError("Message Send Error", fmt.Errorf("Received invalid response description: %s", response.Description)) + logger.Error(fmt.Errorf("Received invalid response description: %s", response.Description)) break } } diff --git a/handlers/mtarget/mtarget.go b/handlers/mtarget/mtarget.go index 724c08091..70a7143b8 100644 --- a/handlers/mtarget/mtarget.go +++ b/handlers/mtarget/mtarget.go @@ -147,8 +147,8 @@ func (h *handler) receiveMsg(ctx context.Context, c courier.Channel, w http.Resp return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for MT channel") @@ -175,16 +175,13 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat msgURL, _ := url.Parse(sendURL) msgURL.RawQuery = params.Encode() req, err := http.NewRequest(http.MethodPost, msgURL.String(), nil) - if err != nil { return nil, err } - trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { - break + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return status, nil } // parse our response for our status code and ticket (external id) @@ -197,15 +194,15 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat // "ticket": "760eeaa0-5034-11e7-bb92-00000a0a643a" // }] // } - code, _ := jsonparser.GetString(trace.ResponseBody, "results", "[0]", "code") - externalID, _ := jsonparser.GetString(trace.ResponseBody, "results", "[0]", "ticket") + code, _ := jsonparser.GetString(respBody, "results", "[0]", "code") + externalID, _ := jsonparser.GetString(respBody, "results", "[0]", "ticket") if code == "0" && externalID != "" { // all went well, set ourselves to wired status.SetStatus(courier.MsgWired) status.SetExternalID(externalID) } else { status.SetStatus(courier.MsgFailed) - log.WithError("Message Send Error", fmt.Errorf("Error status code, failing permanently")) + logger.Error(fmt.Errorf("Error status code, failing permanently")) break } } diff --git a/handlers/nexmo/nexmo.go b/handlers/nexmo/nexmo.go index c63d0555d..929845e6a 100644 --- a/handlers/nexmo/nexmo.go +++ b/handlers/nexmo/nexmo.go @@ -117,8 +117,8 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { nexmoAPIKey := msg.Channel().StringConfigForKey(configNexmoAPIKey, "") if nexmoAPIKey == "" { return nil, fmt.Errorf("no nexmo API key set for NX channel") diff --git a/handlers/novo/novo.go b/handlers/novo/novo.go index 4c2f20d4f..be3e1af92 100644 --- a/handlers/novo/novo.go +++ b/handlers/novo/novo.go @@ -77,8 +77,8 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { merchantID := msg.Channel().StringConfigForKey(configMerchantId, "") if merchantID == "" { return nil, fmt.Errorf("no merchant_id set for NV channel") @@ -110,23 +110,19 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat return nil, err } - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - responseMsgStatus, _ := jsonparser.GetString(trace.ResponseBody, "status") + responseMsgStatus, _ := jsonparser.GetString(respBody, "status") // we always get 204 on success if responseMsgStatus == "FINISHED" { status.SetStatus(courier.MsgWired) } else { status.SetStatus(courier.MsgFailed) - log.WithError("Message Send Error", fmt.Errorf("received invalid response")) + logger.Error(fmt.Errorf("received invalid response")) break } } diff --git a/handlers/playmobile/playmobile.go b/handlers/playmobile/playmobile.go index 8499727be..331ca1183 100644 --- a/handlers/playmobile/playmobile.go +++ b/handlers/playmobile/playmobile.go @@ -144,8 +144,8 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. return handlers.WriteMsgsAndResponse(ctx, h, msgs, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(configUsername, "") if username == "" { return nil, fmt.Errorf("no username set for PM channel") @@ -196,21 +196,12 @@ func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, _, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - if trace.Response != nil && trace.Response.StatusCode == 200 { - status.SetStatus(courier.MsgWired) - } else { - log.WithError("Message Send Error", fmt.Errorf("received invalid response")) - break - } + status.SetStatus(courier.MsgWired) } return status, nil diff --git a/handlers/plivo/plivo.go b/handlers/plivo/plivo.go index 49384c3af..16c033352 100644 --- a/handlers/plivo/plivo.go +++ b/handlers/plivo/plivo.go @@ -135,8 +135,8 @@ type mtPayload struct { Method string `json:"method"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { authID := msg.Channel().StringConfigForKey(configPlivoAuthID, "") authToken := msg.Channel().StringConfigForKey(configPlivoAuthToken, "") plivoAppID := msg.Channel().StringConfigForKey(configPlivoAPPID, "") diff --git a/handlers/redrabbit/redrabbit.go b/handlers/redrabbit/redrabbit.go index e0ba6fda1..b96f29de1 100644 --- a/handlers/redrabbit/redrabbit.go +++ b/handlers/redrabbit/redrabbit.go @@ -35,8 +35,8 @@ func (h *handler) Initialize(s courier.Server) error { return nil } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") password := msg.Channel().StringConfigForKey(courier.ConfigPassword, "") if username == "" || password == "" { @@ -72,9 +72,8 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat return nil, err } - trace, err := handlers.MakeHTTPRequest(req) - status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) - if err != nil { + resp, _, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/rocketchat/rocketchat.go b/handlers/rocketchat/rocketchat.go index 50dc9e191..ff1cbb6d9 100644 --- a/handlers/rocketchat/rocketchat.go +++ b/handlers/rocketchat/rocketchat.go @@ -109,7 +109,7 @@ type mtPayload struct { Attachments []Attachment `json:"attachments,omitempty"` } -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { baseURL := msg.Channel().StringConfigForKey(configBaseURL, "") secret := msg.Channel().StringConfigForKey(configSecret, "") botUsername := msg.Channel().StringConfigForKey(configBotUsername, "") diff --git a/handlers/shaqodoon/shaqodoon.go b/handlers/shaqodoon/shaqodoon.go index 4aaad63a7..c4beb87f2 100644 --- a/handlers/shaqodoon/shaqodoon.go +++ b/handlers/shaqodoon/shaqodoon.go @@ -83,8 +83,8 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { sendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, "") if sendURL == "" { return nil, fmt.Errorf("missing send_url for SQ channel") @@ -114,12 +114,13 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - trace, err := handlers.MakeInsecureHTTPRequest(req) - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) - if err == nil { - status.SetStatus(courier.MsgWired) + + resp, _, err := handlers.RequestHTTPInsecure(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return status, nil } + + status.SetStatus(courier.MsgWired) return status, nil } diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index ca3eca12c..73b3de513 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -150,7 +150,7 @@ func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file return filePath, nil } -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { botToken := msg.Channel().StringConfigForKey(configBotToken, "") if botToken == "" { return nil, fmt.Errorf("missing bot token for SL/slack channel") diff --git a/handlers/smscentral/smscentral.go b/handlers/smscentral/smscentral.go index 0d711540b..8847c3258 100644 --- a/handlers/smscentral/smscentral.go +++ b/handlers/smscentral/smscentral.go @@ -9,7 +9,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/pkg/errors" ) /* @@ -63,8 +62,8 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for SC channel") @@ -75,6 +74,8 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat return nil, fmt.Errorf("no password set for SC channel") } + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + // build our request form := url.Values{ "user": []string{username}, @@ -89,19 +90,11 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) - if err != nil { + resp, _, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - if trace.Response.StatusCode/100 != 2 { - return status, errors.Errorf("Got non-200 response [%d] from API", trace.Response.StatusCode) - } - status.SetStatus(courier.MsgWired) return status, nil diff --git a/handlers/start/start.go b/handlers/start/start.go index 59d10bc88..af2e4865f 100644 --- a/handlers/start/start.go +++ b/handlers/start/start.go @@ -120,7 +120,7 @@ type mtResponse struct { State string `xml:"state"` } -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for ST channel: %s", msg.Channel().UUID()) diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index 577f71ce1..c070a6b7e 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -187,8 +187,8 @@ func (h *handler) sendMsgPart(msg courier.Msg, token string, path string, form u return "", log, false, errors.Errorf("no 'result.message_id' in response") } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { confAuth := msg.Channel().ConfigForKey(courier.ConfigAuthToken, "") authToken, isStr := confAuth.(string) if !isStr || authToken == "" { diff --git a/handlers/telesom/telesom.go b/handlers/telesom/telesom.go index 9a3d98421..33e44ceb2 100644 --- a/handlers/telesom/telesom.go +++ b/handlers/telesom/telesom.go @@ -64,8 +64,8 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for TS channel") diff --git a/handlers/test.go b/handlers/test.go index d420c5990..1d144e810 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -267,8 +267,10 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour testCase.SendPrep(server, handler, channel, msg) } + logger := courier.NewChannelLoggerForSend(msg) + ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*10) - status, err := handler.SendMsg(ctx, msg) + status, err := handler.Send(ctx, msg, logger) cancel() if testCase.Error != "" { diff --git a/handlers/thinq/thinq.go b/handlers/thinq/thinq.go index 626cd3976..597d750eb 100644 --- a/handlers/thinq/thinq.go +++ b/handlers/thinq/thinq.go @@ -127,8 +127,8 @@ type mtMessage struct { Message string `json:"message"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(_ context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { accountID := msg.Channel().StringConfigForKey(configAccountID, "") if accountID == "" { return nil, fmt.Errorf("no account id set for TQ channel") diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index ac8db61ca..658f7c5ec 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -199,8 +199,8 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { // build our callback URL callbackDomain := msg.Channel().CallbackDomain(h.Server().Config().Domain) callbackURL := fmt.Sprintf("https://%s/c/%s/%s/status?id=%d&action=callback", callbackDomain, strings.ToLower(h.ChannelType().String()), msg.Channel().UUID(), msg.ID()) diff --git a/handlers/twitter/twitter.go b/handlers/twitter/twitter.go index 92185ceb2..2ffcb64e2 100644 --- a/handlers/twitter/twitter.go +++ b/handlers/twitter/twitter.go @@ -255,7 +255,7 @@ type mtAttachment struct { } `json:"media"` } -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { apiKey := msg.Channel().StringConfigForKey(configAPIKey, "") apiSecret := msg.Channel().StringConfigForKey(configAPISecret, "") accessToken := msg.Channel().StringConfigForKey(configAccessToken, "") diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index 3631c0bd8..f220f145f 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -309,8 +309,8 @@ type mtPayload struct { Keyboard *Keyboard `json:"keyboard,omitempty"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { authToken := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if authToken == "" { return nil, fmt.Errorf("missing auth token in config") diff --git a/handlers/vk/vk.go b/handlers/vk/vk.go index dc80a014a..6745e1b6f 100644 --- a/handlers/vk/vk.go +++ b/handlers/vk/vk.go @@ -386,7 +386,7 @@ func takeFirstAttachmentUrl(payload moNewMessagePayload) string { return "" } -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) params := buildApiBaseParams(msg.Channel()) diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index 980755132..093e3f4ed 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -511,7 +511,7 @@ func mockAttachmentURLs(mediaServer *httptest.Server, testCases []ChannelSendTes return casesWithMockedUrls } -func TestSendMsg(t *testing.T) { +func TestSend(t *testing.T) { mediaServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { defer req.Body.Close() res.WriteHeader(200) diff --git a/handlers/wavy/wavy.go b/handlers/wavy/wavy.go index 8315d8afc..5b02ca819 100644 --- a/handlers/wavy/wavy.go +++ b/handlers/wavy/wavy.go @@ -138,8 +138,8 @@ type mtPayload struct { Message string `json:"messageText"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for %s channel", msg.Channel().ChannelType()) @@ -170,15 +170,12 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("username", username) req.Header.Set("authenticationtoken", token) - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - externalID, _ := jsonparser.GetString(trace.ResponseBody, "id") + externalID, _ := jsonparser.GetString(respBody, "id") if externalID != "" { status.SetExternalID(externalID) } diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index d93a158db..dafcb8ae1 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -235,8 +235,8 @@ type mtPayload struct { } `json:"text"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { accessToken, err := h.getAccessToken(msg.Channel()) if err != nil { return nil, err diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index fcacf88f6..263262347 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -495,8 +495,8 @@ type mtErrorPayload struct { // whatsapp only allows messages up to 4096 chars const maxMsgLength = 4096 -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { start := time.Now() conn := h.Backend().RedisPool().Get() defer conn.Close() diff --git a/handlers/yo/yo.go b/handlers/yo/yo.go index de1292f1e..84d0f7b3d 100644 --- a/handlers/yo/yo.go +++ b/handlers/yo/yo.go @@ -96,8 +96,8 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{dbMsg}, w, r) } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for YO channel") @@ -130,15 +130,12 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - - if err != nil { - continue + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return status, nil } - responseQS, _ := url.ParseQuery(string(trace.ResponseBody)) + responseQS, _ := url.ParseQuery(string(respBody)) // check whether we were blacklisted createMessage, _ := responseQS["ybs_autocreate_message"] diff --git a/handlers/zenvia/zenvia.go b/handlers/zenvia/zenvia.go index a234d0f13..97eb289b7 100644 --- a/handlers/zenvia/zenvia.go +++ b/handlers/zenvia/zenvia.go @@ -195,8 +195,8 @@ type mtPayload struct { Contents []mtContent `json:"contents"` } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { channel := msg.Channel() token := channel.StringConfigForKey(courier.ConfigAPIKey, "") @@ -259,18 +259,14 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.Header.Set("X-API-TOKEN", token) - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - externalID, err := jsonparser.GetString(trace.ResponseBody, "id") + externalID, err := jsonparser.GetString(respBody, "id") if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to get id from body")) + logger.Error(errors.Errorf("unable to get id from body")) return status, nil } diff --git a/handlers/zenviaold/zenviaold.go b/handlers/zenviaold/zenviaold.go index a95338f7a..f0093bade 100644 --- a/handlers/zenviaold/zenviaold.go +++ b/handlers/zenviaold/zenviaold.go @@ -162,8 +162,8 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } -// SendMsg sends the passed in message, returning any error -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +// Send sends the given message, logging any HTTP calls or errors +func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for ZV channel") @@ -195,20 +195,16 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Accept", "application/json") req.SetBasicAuth(username, password) - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } // was this request successful? - responseMsgStatus, _ := jsonparser.GetString(trace.ResponseBody, "sendSmsResponse", "statusCode") + responseMsgStatus, _ := jsonparser.GetString(respBody, "sendSmsResponse", "statusCode") msgStatus, found := statusMapping[responseMsgStatus] if msgStatus == courier.MsgErrored || !found { - log.WithError("Message Send Error", errors.Errorf("received non-success response from Zenvia '%s'", responseMsgStatus)) + logger.Error(errors.Errorf("received non-success response: '%s'", responseMsgStatus)) return status, nil } diff --git a/sender.go b/sender.go index 094e1b437..37949ccf0 100644 --- a/sender.go +++ b/sender.go @@ -154,7 +154,6 @@ func (w *Sender) Stop() { func (w *Sender) sendMessage(msg Msg) { log := logrus.WithField("comp", "sender").WithField("sender_id", w.id).WithField("channel_uuid", msg.Channel().UUID()) - var status MsgStatus server := w.foreman.server backend := server.Backend() @@ -189,21 +188,31 @@ func (w *Sender) sendMessage(msg Msg) { log.WithError(err).Error("error looking up msg was sent") } + var status MsgStatus + logger := NewChannelLoggerForSend(msg) + if sent { // if this message was already sent, create a wired status for it status = backend.NewMsgStatusForID(msg.Channel(), msg.ID(), MsgWired) log.Warning("duplicate send, marking as wired") } else { // send our message - status, err = server.SendMsg(sendCTX, msg) + status, err = server.SendMsg(sendCTX, msg, logger) duration := time.Now().Sub(start) secondDuration := float64(duration) / float64(time.Second) + // handlers can currently return logs either via the logger or on the status object + if status != nil { + logger.logs = append(logger.logs, status.Logs()...) + } + if err != nil { log.WithError(err).WithField("elapsed", duration).Error("error sending message") + logger.Error(err) + + // possible for handlers to only return an error in which case we construct an error status if status == nil { status = backend.NewMsgStatusForID(msg.Channel(), msg.ID(), MsgErrored) - status.AddLog(NewChannelLogFromError("Sending Error", msg.Channel(), msg.ID(), duration, err)) } } @@ -227,7 +236,7 @@ func (w *Sender) sendMessage(msg Msg) { } // write our logs as well - err = backend.WriteChannelLogs(writeCTX, status.Logs()) + err = backend.WriteChannelLogs(writeCTX, logger.Logs()) if err != nil { log.WithError(err).Info("error writing msg logs") } diff --git a/server.go b/server.go index 4783667fd..55aa1e8b3 100644 --- a/server.go +++ b/server.go @@ -31,7 +31,7 @@ type Server interface { AddHandlerRoute(handler ChannelHandler, method string, action string, handlerFunc ChannelHandleFunc) - SendMsg(context.Context, Msg) (MsgStatus, error) + SendMsg(context.Context, Msg, *ChannelLogger) (MsgStatus, error) Backend() Backend @@ -202,7 +202,7 @@ func (s *server) Stop() error { return nil } -func (s *server) SendMsg(ctx context.Context, msg Msg) (MsgStatus, error) { +func (s *server) SendMsg(ctx context.Context, msg Msg, logger *ChannelLogger) (MsgStatus, error) { // find the handler for this message type handler, found := activeHandlers[msg.Channel().ChannelType()] if !found { @@ -210,7 +210,7 @@ func (s *server) SendMsg(ctx context.Context, msg Msg) (MsgStatus, error) { } // have the handler send it - return handler.SendMsg(ctx, msg) + return handler.Send(ctx, msg, logger) } func (s *server) WaitGroup() *sync.WaitGroup { return s.waitGroup } From 1a914277e63d6ceecc9d830d4e59f7ed1c29b016 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 10 Aug 2022 10:36:35 -0500 Subject: [PATCH 055/294] Cleanup channel send test cases --- .../africastalking/africastalking_test.go | 88 ++- handlers/arabiacell/arabiacell_test.go | 62 +- handlers/blackmyna/blackmyna_test.go | 88 ++- handlers/bongolive/bongolive_test.go | 66 +- handlers/burstsms/burstsms_test.go | 26 +- handlers/chikka/chikka_test.go | 62 +- handlers/clickatell/clickatell_test.go | 40 +- handlers/clickmobile/clickmobile_test.go | 48 +- handlers/clicksend/clicksend_test.go | 44 +- handlers/dart/dart_test.go | 50 +- handlers/discord/discord_test.go | 6 +- handlers/dmark/dmark_test.go | 36 +- handlers/external/external_test.go | 376 +++++----- handlers/facebook/facebook_test.go | 100 +-- handlers/facebookapp/facebookapp_test.go | 639 ++++++++++------- handlers/firebase/firebase_test.go | 68 +- handlers/freshchat/freshchat_test.go | 56 +- handlers/globe/globe_test.go | 36 +- .../highconnection/highconnection_test.go | 78 +-- handlers/hormuud/hormuud_test.go | 42 +- handlers/i2sms/i2sms_test.go | 26 +- handlers/infobip/infobip_test.go | 72 +- handlers/jasmin/jasmin_test.go | 48 +- handlers/jiochat/jiochat_test.go | 62 +- handlers/junebug/junebug_test.go | 82 +-- handlers/kaleyra/kaleyra_test.go | 116 ++-- handlers/kannel/kannel_test.go | 78 +-- handlers/line/line_test.go | 118 ++-- handlers/m3tech/m3tech_test.go | 44 +- handlers/macrokiosk/macrokiosk_test.go | 88 +-- handlers/mblox/mblox_test.go | 88 +-- handlers/messangi/messangi_test.go | 57 +- handlers/mtarget/mtarget_test.go | 40 +- handlers/nexmo/nexmo_test.go | 66 +- handlers/novo/novo_test.go | 65 +- handlers/playmobile/playmobile_test.go | 116 ++-- handlers/plivo/plivo_test.go | 88 +-- handlers/redrabbit/redrabbit_test.go | 50 +- handlers/rocketchat/rocketchat_test.go | 56 +- handlers/shaqodoon/shaqodoon_test.go | 40 +- handlers/slack/slack_test.go | 66 +- handlers/smscentral/smscentral_test.go | 40 +- handlers/start/start_test.go | 86 +-- handlers/telegram/telegram_test.go | 205 ++++-- handlers/telesom/telesom_test.go | 48 +- handlers/test.go | 140 ++-- handlers/thinq/thinq_test.go | 48 +- handlers/twiml/twiml_test.go | 542 +++++++++------ handlers/twitter/twitter_test.go | 78 +-- handlers/viber/viber_test.go | 158 ++--- handlers/vk/vk_test.go | 66 +- handlers/wavy/wavy_test.go | 28 +- handlers/wechat/wechat_test.go | 62 +- handlers/whatsapp/whatsapp_test.go | 645 ++++++++++-------- handlers/yo/yo_test.go | 60 +- handlers/zenvia/zenvia_test.go | 172 ++--- handlers/zenviaold/zenviaold_test.go | 86 +-- 57 files changed, 3235 insertions(+), 2706 deletions(-) diff --git a/handlers/africastalking/africastalking_test.go b/handlers/africastalking/africastalking_test.go index c3941a58a..2ff815581 100644 --- a/handlers/africastalking/africastalking_test.go +++ b/handlers/africastalking/africastalking_test.go @@ -61,41 +61,65 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - Text: "Simple Message ☺", URN: "tel:+250788383383", - Status: "W", ExternalID: "1002", - ResponseBody: `{ "SMSMessageData": {"Recipients": [{"status": "Success", "messageId": "1002"}] } }`, ResponseStatus: 200, - Headers: map[string]string{"apikey": "KEY"}, - PostParams: map[string]string{"message": "Simple Message ☺", "username": "Username", "to": "+250788383383", "from": "2020"}, - SendPrep: setSendURL}, - {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", ExternalID: "1002", - ResponseBody: `{ "SMSMessageData": {"Recipients": [{"status": "Success", "messageId": "1002"}] } }`, ResponseStatus: 200, - PostParams: map[string]string{"message": "My pic!\nhttps://foo.bar/image.jpg"}, - SendPrep: setSendURL}, - {Label: "No External Id", - Text: "No External ID", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "SMSMessageData": {"Recipients": [{"status": "Failed" }] } }`, ResponseStatus: 200, - PostParams: map[string]string{"message": `No External ID`}, - SendPrep: setSendURL}, - {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "failed" }`, ResponseStatus: 401, - PostParams: map[string]string{"message": `Error Message`}, - SendPrep: setSendURL}, + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "SMSMessageData": {"Recipients": [{"status": "Success", "messageId": "1002"}] } }`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"apikey": "KEY"}, + ExpectedPostParams: map[string]string{"message": "Simple Message ☺", "username": "Username", "to": "+250788383383", "from": "2020"}, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{ "SMSMessageData": {"Recipients": [{"status": "Success", "messageId": "1002"}] } }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"message": "My pic!\nhttps://foo.bar/image.jpg"}, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "No External Id", + MsgText: "No External ID", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "SMSMessageData": {"Recipients": [{"status": "Failed" }] } }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"message": `No External ID`}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "error": "failed" }`, + MockResponseStatus: 401, + ExpectedPostParams: map[string]string{"message": `Error Message`}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } var sharedSendTestCases = []ChannelSendTestCase{ - {Label: "Shared Send", - Text: "Simple Message ☺", URN: "tel:+250788383383", - Status: "W", ExternalID: "1002", - ResponseBody: `{ "SMSMessageData": {"Recipients": [{"status": "Success", "messageId": "1002"}] } }`, ResponseStatus: 200, - Headers: map[string]string{"apikey": "KEY"}, - PostParams: map[string]string{"message": "Simple Message ☺", "username": "Username", "to": "+250788383383", "from": ""}, - SendPrep: setSendURL}, + { + Label: "Shared Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "SMSMessageData": {"Recipients": [{"status": "Success", "messageId": "1002"}] } }`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"apikey": "KEY"}, + ExpectedPostParams: map[string]string{"message": "Simple Message ☺", "username": "Username", "to": "+250788383383", "from": ""}, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/arabiacell/arabiacell_test.go b/handlers/arabiacell/arabiacell_test.go index 708addfd7..aed990867 100644 --- a/handlers/arabiacell/arabiacell_test.go +++ b/handlers/arabiacell/arabiacell_test.go @@ -38,15 +38,18 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - Text: "Simple Message ☺", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", ExternalID: "external1", - ResponseBody: ` + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: ` 204 MT is successfully sent external1 -`, ResponseStatus: 200, - PostParams: map[string]string{ +`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{ "userName": "user1", "password": "pass1", "handlerType": "send_msg", @@ -55,22 +58,37 @@ var defaultSendTestCases = []ChannelSendTestCase{ "messageBody": "Simple Message ☺\nhttps://foo.bar/image.jpg", "chargingLevel": "0", }, - SendPrep: setSendURL}, - {Label: "Invalid XML", - Text: "Invalid XML", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `not xml`, ResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Error Response", - Text: "Error Response", URN: "tel:+250788383383", - Status: "F", - ResponseBody: `501failure`, ResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `Bad Gateway`, ResponseStatus: 501, - SendPrep: setSendURL}, + ExpectedStatus: "W", + ExpectedExternalID: "external1", + SendPrep: setSendURL, + }, + { + Label: "Invalid XML", + MsgText: "Invalid XML", + MsgURN: "tel:+250788383383", + MockResponseBody: `not xml`, + MockResponseStatus: 200, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error Response", + MsgText: "Error Response", + MsgURN: "tel:+250788383383", + MockResponseBody: `501failure`, + MockResponseStatus: 200, + ExpectedStatus: "F", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `Bad Gateway`, + MockResponseStatus: 501, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/blackmyna/blackmyna_test.go b/handlers/blackmyna/blackmyna_test.go index 78be81e60..dc3eb4d76 100644 --- a/handlers/blackmyna/blackmyna_test.go +++ b/handlers/blackmyna/blackmyna_test.go @@ -52,38 +52,62 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", ExternalID: "1002", - ResponseBody: `[{"id": "1002"}]`, ResponseStatus: 200, - Headers: map[string]string{"Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ="}, - PostParams: map[string]string{"message": "Simple Message", "address": "+250788383383", "senderaddress": "2020"}, - SendPrep: setSendURL}, - {Label: "Unicode Send", - Text: "☺", URN: "tel:+250788383383", - Status: "W", ExternalID: "1002", - ResponseBody: `[{"id": "1002"}]`, ResponseStatus: 200, - PostParams: map[string]string{"message": "☺", "address": "+250788383383", "senderaddress": "2020"}, - SendPrep: setSendURL}, - {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", ExternalID: "1002", - ResponseBody: `[{ "id": "1002" }]`, ResponseStatus: 200, - PostParams: map[string]string{"message": "My pic!\nhttps://foo.bar/image.jpg", "address": "+250788383383", "senderaddress": "2020"}, - SendPrep: setSendURL}, - {Label: "No External Id", - Text: "No External ID", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "failed" }`, ResponseStatus: 200, - Error: "no external id returned in body", - PostParams: map[string]string{"message": `No External ID`, "address": "+250788383383", "senderaddress": "2020"}, - SendPrep: setSendURL}, - {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "failed" }`, ResponseStatus: 401, - PostParams: map[string]string{"message": `Error Message`, "address": "+250788383383", "senderaddress": "2020"}, - SendPrep: setSendURL}, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `[{"id": "1002"}]`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ="}, + ExpectedPostParams: map[string]string{"message": "Simple Message", "address": "+250788383383", "senderaddress": "2020"}, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "tel:+250788383383", + MockResponseBody: `[{"id": "1002"}]`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"message": "☺", "address": "+250788383383", "senderaddress": "2020"}, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `[{ "id": "1002" }]`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"message": "My pic!\nhttps://foo.bar/image.jpg", "address": "+250788383383", "senderaddress": "2020"}, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "No External Id", + MsgText: "No External ID", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "error": "failed" }`, + MockResponseStatus: 200, + ExpectedError: "no external id returned in body", + ExpectedPostParams: map[string]string{"message": `No External ID`, "address": "+250788383383", "senderaddress": "2020"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "error": "failed" }`, + MockResponseStatus: 401, + ExpectedPostParams: map[string]string{"message": `Error Message`, "address": "+250788383383", "senderaddress": "2020"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/bongolive/bongolive_test.go b/handlers/bongolive/bongolive_test.go index a77ec222b..f68a79407 100644 --- a/handlers/bongolive/bongolive_test.go +++ b/handlers/bongolive/bongolive_test.go @@ -50,12 +50,14 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - Text: "Simple Message ☺", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `{"results": [{"status": "0", "msgid": "123"}]}`, - ResponseStatus: 200, - URLParams: map[string]string{ + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{"results": [{"status": "0", "msgid": "123"}]}`, + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{ "USERNAME": "user1", "PASSWORD": "pass1", "SOURCEADDR": "2020", @@ -63,14 +65,18 @@ var defaultSendTestCases = []ChannelSendTestCase{ "DLR": "1", "MESSAGE": "Simple Message ☺\nhttps://foo.bar/image.jpg", }, - ExternalID: "123", - SendPrep: setSendURL}, - {Label: "Bad Status", - Text: "Simple Message ☺", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "E", - ResponseBody: `{"results": [{"status": "3"}]}`, - ResponseStatus: 200, - URLParams: map[string]string{ + ExpectedStatus: "W", + ExpectedExternalID: "123", + SendPrep: setSendURL, + }, + { + Label: "Bad Status", + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{"results": [{"status": "3"}]}`, + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{ "USERNAME": "user1", "PASSWORD": "pass1", "SOURCEADDR": "2020", @@ -78,17 +84,27 @@ var defaultSendTestCases = []ChannelSendTestCase{ "DLR": "1", "MESSAGE": "Simple Message ☺\nhttps://foo.bar/image.jpg", }, - SendPrep: setSendURL}, - {Label: "Error status 403", - Text: "Error Response", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{"results": [{"status": "1", "msgid": "123"}]}`, ResponseStatus: 403, - SendPrep: setSendURL}, - {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `Bad Gateway`, ResponseStatus: 501, - SendPrep: setSendURL}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error status 403", + MsgText: "Error Response", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"results": [{"status": "1", "msgid": "123"}]}`, + MockResponseStatus: 403, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `Bad Gateway`, + MockResponseStatus: 501, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/burstsms/burstsms_test.go b/handlers/burstsms/burstsms_test.go index c06790144..c6b501956 100644 --- a/handlers/burstsms/burstsms_test.go +++ b/handlers/burstsms/burstsms_test.go @@ -48,29 +48,29 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", ExternalID: "19835", - ResponseBody: `{ "message_id": 19835, "recipients": 3, "cost": 1.000 }`, ResponseStatus: 200, - PostParams: map[string]string{ + MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", ExpectedExternalID: "19835", + MockResponseBody: `{ "message_id": 19835, "recipients": 3, "cost": 1.000 }`, MockResponseStatus: 200, + ExpectedPostParams: map[string]string{ "to": "250788383383", "message": "Simple Message ☺\nhttps://foo.bar/image.jpg", "from": "2020", }, SendPrep: setSendURL}, {Label: "Invalid JSON", - Text: "Invalid JSON", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `not json`, ResponseStatus: 200, + MsgText: "Invalid JSON", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `not json`, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Error Response", - Text: "Error Response", URN: "tel:+250788383383", - Status: "F", - ResponseBody: `{ "message_id": 0 }`, ResponseStatus: 200, + MsgText: "Error Response", MsgURN: "tel:+250788383383", + ExpectedStatus: "F", + MockResponseBody: `{ "message_id": 0 }`, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `Bad Gateway`, ResponseStatus: 501, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `Bad Gateway`, MockResponseStatus: 501, SendPrep: setSendURL}, } diff --git a/handlers/chikka/chikka_test.go b/handlers/chikka/chikka_test.go index b31a9533e..cc940d2a6 100644 --- a/handlers/chikka/chikka_test.go +++ b/handlers/chikka/chikka_test.go @@ -54,10 +54,10 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+63911231234", - Status: "W", - ResponseBody: "Success", ResponseStatus: 200, - PostParams: map[string]string{ + MsgText: "Simple Message", MsgURN: "tel:+63911231234", + ExpectedStatus: "W", + MockResponseBody: "Success", MockResponseStatus: 200, + ExpectedPostParams: map[string]string{ "message": "Simple Message", "message_type": "SEND", "mobile_number": "63911231234", @@ -69,11 +69,11 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Plain Reply", - Text: "Simple Message", URN: "tel:+63911231234", - Status: "W", - ResponseToExternalID: "external-id", - ResponseBody: "Success", ResponseStatus: 200, - PostParams: map[string]string{ + MsgText: "Simple Message", MsgURN: "tel:+63911231234", + ExpectedStatus: "W", + MsgResponseToExternalID: "external-id", + MockResponseBody: "Success", MockResponseStatus: 200, + ExpectedPostParams: map[string]string{ "message": "Simple Message", "message_type": "REPLY", "request_id": "external-id", @@ -86,11 +86,11 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Failed Reply use Send", - Text: "Simple Message", URN: "tel:+63911231234", - ResponseToExternalID: "external-id", - ResponseBody: `{"status":400,"message":"BAD REQUEST","description":"Invalid\\/Used Request ID"}`, - ResponseStatus: 400, - PostParams: map[string]string{ + MsgText: "Simple Message", MsgURN: "tel:+63911231234", + MsgResponseToExternalID: "external-id", + MockResponseBody: `{"status":400,"message":"BAD REQUEST","description":"Invalid\\/Used Request ID"}`, + MockResponseStatus: 400, + ExpectedPostParams: map[string]string{ "message": "Simple Message", "message_type": "SEND", "mobile_number": "63911231234", @@ -102,10 +102,10 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "tel:+63911231234", - Status: "W", - ResponseBody: "Success", ResponseStatus: 200, - PostParams: map[string]string{ + MsgText: "☺", MsgURN: "tel:+63911231234", + ExpectedStatus: "W", + MockResponseBody: "Success", MockResponseStatus: 200, + ExpectedPostParams: map[string]string{ "message": "☺", "message_type": "SEND", "mobile_number": "63911231234", @@ -117,11 +117,11 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+63911231234", - Status: "W", - ResponseBody: "Success", ResponseStatus: 200, - PostParams: map[string]string{ + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+63911231234", + ExpectedStatus: "W", + MockResponseBody: "Success", MockResponseStatus: 200, + ExpectedPostParams: map[string]string{ "message": "I need to keep adding more things to make it work", "message_type": "SEND", "mobile_number": "63911231234", @@ -133,10 +133,10 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+63911231234", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: "Success", ResponseStatus: 200, - PostParams: map[string]string{ + MsgText: "My pic!", MsgURN: "tel:+63911231234", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: "Success", MockResponseStatus: 200, + ExpectedPostParams: map[string]string{ "message": "My pic!\nhttps://foo.bar/image.jpg", "message_type": "SEND", "mobile_number": "63911231234", @@ -148,10 +148,10 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+63911231234", - Status: "E", - ResponseBody: `ERROR`, ResponseStatus: 401, - PostParams: map[string]string{ + MsgText: "Error Message", MsgURN: "tel:+63911231234", + ExpectedStatus: "E", + MockResponseBody: `ERROR`, MockResponseStatus: 401, + ExpectedPostParams: map[string]string{ "message": "Error Message", "message_type": "SEND", "mobile_number": "63911231234", diff --git a/handlers/clickatell/clickatell_test.go b/handlers/clickatell/clickatell_test.go index 7bf76cec5..a32c7da79 100644 --- a/handlers/clickatell/clickatell_test.go +++ b/handlers/clickatell/clickatell_test.go @@ -19,34 +19,34 @@ var failSendResponse = `{"messages":[],"error":"Two-Way integration error - From var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", ExternalID: "id1002", - URLParams: map[string]string{"content": "Simple Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, - ResponseBody: successSendResponse, ResponseStatus: 200, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", ExpectedExternalID: "id1002", + ExpectedURLParams: map[string]string{"content": "Simple Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, + MockResponseBody: successSendResponse, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "Unicode ☺", URN: "tel:+250788383383", - Status: "W", ExternalID: "id1002", - URLParams: map[string]string{"content": "Unicode ☺", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, - ResponseBody: successSendResponse, ResponseStatus: 200, + MsgText: "Unicode ☺", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", ExpectedExternalID: "id1002", + ExpectedURLParams: map[string]string{"content": "Unicode ☺", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, + MockResponseBody: successSendResponse, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", ExternalID: "id1002", - URLParams: map[string]string{"content": "My pic!\nhttps://foo.bar/image.jpg", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, - ResponseBody: successSendResponse, ResponseStatus: 200, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", ExpectedExternalID: "id1002", + ExpectedURLParams: map[string]string{"content": "My pic!\nhttps://foo.bar/image.jpg", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, + MockResponseBody: successSendResponse, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - URLParams: map[string]string{"content": "Error Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, - ResponseBody: `Error`, ResponseStatus: 400, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + ExpectedURLParams: map[string]string{"content": "Error Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, + MockResponseBody: `Error`, MockResponseStatus: 400, SendPrep: setSendURL}, {Label: "Error Response", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - URLParams: map[string]string{"content": "Error Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, - ResponseBody: failSendResponse, ResponseStatus: 200, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + ExpectedURLParams: map[string]string{"content": "Error Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, + MockResponseBody: failSendResponse, MockResponseStatus: 200, SendPrep: setSendURL}, } diff --git a/handlers/clickmobile/clickmobile_test.go b/handlers/clickmobile/clickmobile_test.go index d02da0a64..be69ca267 100644 --- a/handlers/clickmobile/clickmobile_test.go +++ b/handlers/clickmobile/clickmobile_test.go @@ -100,33 +100,33 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - ResponseBody: `{"code":"000","desc":"Operation successful.","data":{"new_record_id":"9"}}`, ResponseStatus: 200, - RequestBody: `{"app_id":"001-app","org_id":"001-org","user_id":"Username","timestamp":"20180411182430","auth_key":"3e1347ddb444d13aa23d11e097602be0","operation":"send","reference":"10","message_type":"1","src_address":"2020","dst_address":"+250788383383","message":"Simple Message"}`, - Headers: map[string]string{"Content-Type": "application/json"}, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: `{"code":"000","desc":"Operation successful.","data":{"new_record_id":"9"}}`, MockResponseStatus: 200, + ExpectedRequestBody: `{"app_id":"001-app","org_id":"001-org","user_id":"Username","timestamp":"20180411182430","auth_key":"3e1347ddb444d13aa23d11e097602be0","operation":"send","reference":"10","message_type":"1","src_address":"2020","dst_address":"+250788383383","message":"Simple Message"}`, + ExpectedHeaders: map[string]string{"Content-Type": "application/json"}, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "tel:+250788383383", - Status: "W", - ResponseBody: `{"code":"000","desc":"Operation successful.","data":{"new_record_id":"9"}}`, ResponseStatus: 200, - RequestBody: `{"app_id":"001-app","org_id":"001-org","user_id":"Username","timestamp":"20180411182430","auth_key":"3e1347ddb444d13aa23d11e097602be0","operation":"send","reference":"10","message_type":"1","src_address":"2020","dst_address":"+250788383383","message":"☺"}`, - Headers: map[string]string{"Content-Type": "application/json"}, - SendPrep: setSendURL}, + MsgText: "☺", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: `{"code":"000","desc":"Operation successful.","data":{"new_record_id":"9"}}`, MockResponseStatus: 200, + ExpectedRequestBody: `{"app_id":"001-app","org_id":"001-org","user_id":"Username","timestamp":"20180411182430","auth_key":"3e1347ddb444d13aa23d11e097602be0","operation":"send","reference":"10","message_type":"1","src_address":"2020","dst_address":"+250788383383","message":"☺"}`, + ExpectedHeaders: map[string]string{"Content-Type": "application/json"}, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{"code":"001","desc":"Database SQL Error"}`, ResponseStatus: 401, - RequestBody: `{"app_id":"001-app","org_id":"001-org","user_id":"Username","timestamp":"20180411182430","auth_key":"3e1347ddb444d13aa23d11e097602be0","operation":"send","reference":"10","message_type":"1","src_address":"2020","dst_address":"+250788383383","message":"Error Message"}`, - Headers: map[string]string{"Content-Type": "application/json"}, - SendPrep: setSendURL}, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{"code":"001","desc":"Database SQL Error"}`, MockResponseStatus: 401, + ExpectedRequestBody: `{"app_id":"001-app","org_id":"001-org","user_id":"Username","timestamp":"20180411182430","auth_key":"3e1347ddb444d13aa23d11e097602be0","operation":"send","reference":"10","message_type":"1","src_address":"2020","dst_address":"+250788383383","message":"Error Message"}`, + ExpectedHeaders: map[string]string{"Content-Type": "application/json"}, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `{"code":"000","desc":"Operation successful.","data":{"new_record_id":"9"}}`, ResponseStatus: 200, - RequestBody: `{"app_id":"001-app","org_id":"001-org","user_id":"Username","timestamp":"20180411182430","auth_key":"3e1347ddb444d13aa23d11e097602be0","operation":"send","reference":"10","message_type":"1","src_address":"2020","dst_address":"+250788383383","message":"My pic!\nhttps://foo.bar/image.jpg"}`, - Headers: map[string]string{"Content-Type": "application/json"}, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: `{"code":"000","desc":"Operation successful.","data":{"new_record_id":"9"}}`, MockResponseStatus: 200, + ExpectedRequestBody: `{"app_id":"001-app","org_id":"001-org","user_id":"Username","timestamp":"20180411182430","auth_key":"3e1347ddb444d13aa23d11e097602be0","operation":"send","reference":"10","message_type":"1","src_address":"2020","dst_address":"+250788383383","message":"My pic!\nhttps://foo.bar/image.jpg"}`, + ExpectedHeaders: map[string]string{"Content-Type": "application/json"}, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/clicksend/clicksend_test.go b/handlers/clicksend/clicksend_test.go index 5859d5c2b..c3e55c40e 100644 --- a/handlers/clicksend/clicksend_test.go +++ b/handlers/clicksend/clicksend_test.go @@ -96,33 +96,33 @@ const failureResponse = `{ var sendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - Headers: map[string]string{"Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="}, - ResponseBody: successResponse, ResponseStatus: 200, ExternalID: "BF7AD270-0DE2-418B-B606-71D527D9C1AE", - RequestBody: `{"messages":[{"to":"+250788383383","from":"2020","body":"Simple Message","source":"courier"}]}`, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedHeaders: map[string]string{"Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="}, + MockResponseBody: successResponse, MockResponseStatus: 200, ExpectedExternalID: "BF7AD270-0DE2-418B-B606-71D527D9C1AE", + ExpectedRequestBody: `{"messages":[{"to":"+250788383383","from":"2020","body":"Simple Message","source":"courier"}]}`, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "tel:+250788383383", - Status: "W", - ResponseBody: successResponse, ResponseStatus: 200, ExternalID: "BF7AD270-0DE2-418B-B606-71D527D9C1AE", - RequestBody: `{"messages":[{"to":"+250788383383","from":"2020","body":"☺","source":"courier"}]}`, - SendPrep: setSendURL}, + MsgText: "☺", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: successResponse, MockResponseStatus: 200, ExpectedExternalID: "BF7AD270-0DE2-418B-B606-71D527D9C1AE", + ExpectedRequestBody: `{"messages":[{"to":"+250788383383","from":"2020","body":"☺","source":"courier"}]}`, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: successResponse, ResponseStatus: 200, ExternalID: "BF7AD270-0DE2-418B-B606-71D527D9C1AE", - RequestBody: `{"messages":[{"to":"+250788383383","from":"2020","body":"My pic!\nhttps://foo.bar/image.jpg","source":"courier"}]}`, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: successResponse, MockResponseStatus: 200, ExpectedExternalID: "BF7AD270-0DE2-418B-B606-71D527D9C1AE", + ExpectedRequestBody: `{"messages":[{"to":"+250788383383","from":"2020","body":"My pic!\nhttps://foo.bar/image.jpg","source":"courier"}]}`, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Sending", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `[{"Response": "101"}]`, ResponseStatus: 403, + MsgText: "Error Sending", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `[{"Response": "101"}]`, MockResponseStatus: 403, SendPrep: setSendURL}, {Label: "Failure Response", - Text: "Error Sending", URN: "tel:+250788383383", - Status: "E", - ResponseBody: failureResponse, ResponseStatus: 200, + MsgText: "Error Sending", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: failureResponse, MockResponseStatus: 200, SendPrep: setSendURL}, } diff --git a/handlers/dart/dart_test.go b/handlers/dart/dart_test.go index dbe02107f..3cc1449ff 100644 --- a/handlers/dart/dart_test.go +++ b/handlers/dart/dart_test.go @@ -57,41 +57,41 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - URLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, - ResponseBody: "000", ResponseStatus: 200, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, + MockResponseBody: "000", MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+250788383383", - Status: "W", - URLParams: map[string]string{"message": "I need to keep adding more things to make it work", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10.2"}, - ResponseBody: "000", ResponseStatus: 200, + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedURLParams: map[string]string{"message": "I need to keep adding more things to make it work", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10.2"}, + MockResponseBody: "000", MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - URLParams: map[string]string{"message": "My pic!\nhttps://foo.bar/image.jpg", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, - ResponseBody: "000", ResponseStatus: 200, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + ExpectedURLParams: map[string]string{"message": "My pic!\nhttps://foo.bar/image.jpg", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, + MockResponseBody: "000", MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - URLParams: map[string]string{"message": "Error Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, - ResponseBody: `Error`, ResponseStatus: 400, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + ExpectedURLParams: map[string]string{"message": "Error Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, + MockResponseBody: `Error`, MockResponseStatus: 400, SendPrep: setSendURL}, {Label: "Authentication Error", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "E", - URLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, - ResponseBody: "001", ResponseStatus: 200, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, + MockResponseBody: "001", MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Account Expired", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "E", - URLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, - ResponseBody: "101", ResponseStatus: 200, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, + MockResponseBody: "101", MockResponseStatus: 200, SendPrep: setSendURL}, } diff --git a/handlers/discord/discord_test.go b/handlers/discord/discord_test.go index 49bc6b3d9..4ef0e0be4 100644 --- a/handlers/discord/discord_test.go +++ b/handlers/discord/discord_test.go @@ -32,9 +32,9 @@ var testCases = []ChannelHandleTestCase{ } var sendTestCases = []ChannelSendTestCase{ - {Label: "Simple Send", Text: "Hello World", URN: "discord:694634743521607802", Path: "/discord/rp/send", ResponseStatus: 200, RequestBody: `{"id":"10","text":"Hello World","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":[],"quick_replies":null}`, SendPrep: setSendURL}, - {Label: "Simple Send", Text: "Hello World", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, URN: "discord:694634743521607802", Path: "/discord/rp/send", RequestBody: `{"id":"10","text":"Hello World","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":["https://foo.bar/image.jpg"],"quick_replies":null}`, ResponseStatus: 200, SendPrep: setSendURL}, - {Label: "Simple Send with attachements and Quick Replies", Text: "Hello World", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, QuickReplies: []string{"hello", "world"}, URN: "discord:694634743521607802", Path: "/discord/rp/send", RequestBody: `{"id":"10","text":"Hello World","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":["https://foo.bar/image.jpg"],"quick_replies":["hello","world"]}`, ResponseStatus: 200, SendPrep: setSendURL}, + {Label: "Simple Send", MsgText: "Hello World", MsgURN: "discord:694634743521607802", ExpectedRequestPath: "/discord/rp/send", MockResponseStatus: 200, ExpectedRequestBody: `{"id":"10","text":"Hello World","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":[],"quick_replies":null}`, SendPrep: setSendURL}, + {Label: "Simple Send", MsgText: "Hello World", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MsgURN: "discord:694634743521607802", ExpectedRequestPath: "/discord/rp/send", ExpectedRequestBody: `{"id":"10","text":"Hello World","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":["https://foo.bar/image.jpg"],"quick_replies":null}`, MockResponseStatus: 200, SendPrep: setSendURL}, + {Label: "Simple Send with attachements and Quick Replies", MsgText: "Hello World", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MsgQuickReplies: []string{"hello", "world"}, MsgURN: "discord:694634743521607802", ExpectedRequestPath: "/discord/rp/send", ExpectedRequestBody: `{"id":"10","text":"Hello World","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":["https://foo.bar/image.jpg"],"quick_replies":["hello","world"]}`, MockResponseStatus: 200, SendPrep: setSendURL}, } // setSendURL takes care of setting the send_url to our test server host diff --git a/handlers/dmark/dmark_test.go b/handlers/dmark/dmark_test.go index 2f52a3ffa..08558dc1f 100644 --- a/handlers/dmark/dmark_test.go +++ b/handlers/dmark/dmark_test.go @@ -57,26 +57,26 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", URN: "tel:+250788383383", - Status: "W", ExternalID: "6b1c15d3-cba2-46f7-9a25-78265e58057d", - ResponseBody: `{ "type": "MT", "sms_id": "6b1c15d3-cba2-46f7-9a25-78265e58057d" }`, ResponseStatus: 200, - Headers: map[string]string{"Authorization": "Token Authy"}, - PostParams: map[string]string{"text": "Simple Message ☺", "receiver": "250788383383", "sender": "2020", "dlr_url": "https://localhost/c/dk/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%s"}, - SendPrep: setSendURL}, + MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", ExpectedExternalID: "6b1c15d3-cba2-46f7-9a25-78265e58057d", + MockResponseBody: `{ "type": "MT", "sms_id": "6b1c15d3-cba2-46f7-9a25-78265e58057d" }`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Authorization": "Token Authy"}, + ExpectedPostParams: map[string]string{"text": "Simple Message ☺", "receiver": "250788383383", "sender": "2020", "dlr_url": "https://localhost/c/dk/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%s"}, + SendPrep: setSendURL}, {Label: "Invalid Body", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "failed" }`, ResponseStatus: 200, - Headers: map[string]string{"Authorization": "Token Authy"}, - PostParams: map[string]string{"text": "Error Message", "receiver": "250788383383", "sender": "2020"}, - SendPrep: setSendURL}, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Authorization": "Token Authy"}, + ExpectedPostParams: map[string]string{"text": "Error Message", "receiver": "250788383383", "sender": "2020"}, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "failed" }`, ResponseStatus: 401, - Headers: map[string]string{"Authorization": "Token Authy"}, - PostParams: map[string]string{"text": "Error Message", "receiver": "250788383383", "sender": "2020"}, - SendPrep: setSendURL}, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, + ExpectedHeaders: map[string]string{"Authorization": "Token Authy"}, + ExpectedPostParams: map[string]string{"text": "Error Message", "receiver": "250788383383", "sender": "2020"}, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/external/external_test.go b/handlers/external/external_test.go index 8a9343c68..798bd7d16 100644 --- a/handlers/external/external_test.go +++ b/handlers/external/external_test.go @@ -131,262 +131,262 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var longSendTestCases = []ChannelSendTestCase{ {Label: "Long Send", - Text: "This is a long message that will be longer than 30....... characters", URN: "tel:+250788383383", - QuickReplies: []string{"One"}, - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - URLParams: map[string]string{"text": "characters", "to": "+250788383383", "from": "2020", "quick_reply": "One"}, - SendPrep: setSendURL}, + MsgText: "This is a long message that will be longer than 30....... characters", MsgURN: "tel:+250788383383", + MsgQuickReplies: []string{"One"}, + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "characters", "to": "+250788383383", "from": "2020", "quick_reply": "One"}, + SendPrep: setSendURL}, } var getSendSmartEncodingTestCases = []ChannelSendTestCase{ {Label: "Smart Encoding", - Text: "Fancy “Smart” Quotes", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - URLParams: map[string]string{"text": `Fancy "Smart" Quotes`, "to": "+250788383383", "from": "2020"}, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + MsgText: "Fancy “Smart” Quotes", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": `Fancy "Smart" Quotes`, "to": "+250788383383", "from": "2020"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + SendPrep: setSendURL}, } var postSendSmartEncodingTestCases = []ChannelSendTestCase{ {Label: "Smart Encoding", - Text: "Fancy “Smart” Quotes", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - PostParams: map[string]string{"text": `Fancy "Smart" Quotes`, "to": "+250788383383", "from": "2020"}, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + MsgText: "Fancy “Smart” Quotes", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"text": `Fancy "Smart" Quotes`, "to": "+250788383383", "from": "2020"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + SendPrep: setSendURL}, } var getSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - URLParams: map[string]string{"text": "Simple Message", "to": "+250788383383", "from": "2020"}, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "Simple Message", "to": "+250788383383", "from": "2020"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - URLParams: map[string]string{"text": "☺", "to": "+250788383383", "from": "2020"}, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + MsgText: "☺", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "☺", "to": "+250788383383", "from": "2020"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: "1: Unknown channel", ResponseStatus: 401, - URLParams: map[string]string{"text": `Error Message`, "to": "+250788383383"}, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: "1: Unknown channel", MockResponseStatus: 401, + ExpectedURLParams: map[string]string{"text": `Error Message`, "to": "+250788383383"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `0: Accepted for delivery`, ResponseStatus: 200, - URLParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "+250788383383", "from": "2020"}, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: `0: Accepted for delivery`, MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "+250788383383", "from": "2020"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + SendPrep: setSendURL}, } var postSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - PostParams: map[string]string{"text": "Simple Message", "to": "+250788383383", "from": "2020"}, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "+250788383383", "from": "2020"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - PostParams: map[string]string{"text": "☺", "to": "+250788383383", "from": "2020"}, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + MsgText: "☺", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"text": "☺", "to": "+250788383383", "from": "2020"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: "1: Unknown channel", ResponseStatus: 401, - PostParams: map[string]string{"text": `Error Message`, "to": "+250788383383"}, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: "1: Unknown channel", MockResponseStatus: 401, + ExpectedPostParams: map[string]string{"text": `Error Message`, "to": "+250788383383"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `0: Accepted for delivery`, ResponseStatus: 200, - PostParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "+250788383383", "from": "2020"}, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: `0: Accepted for delivery`, MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "+250788383383", "from": "2020"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + SendPrep: setSendURL}, } var postSendCustomContentTypeTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - PostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020"}, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded; charset=utf-8"}, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded; charset=utf-8"}, + SendPrep: setSendURL}, } var jsonSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - RequestBody: `{ "to":"+250788383383", "text":"Simple Message", "from":"2020", "quick_replies":[] }`, - Headers: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedRequestBody: `{ "to":"+250788383383", "text":"Simple Message", "from":"2020", "quick_replies":[] }`, + ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: `☺ "hi!"`, URN: "tel:+250788383383", - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - RequestBody: `{ "to":"+250788383383", "text":"☺ \"hi!\"", "from":"2020", "quick_replies":[] }`, - Headers: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - SendPrep: setSendURL}, + MsgText: `☺ "hi!"`, MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedRequestBody: `{ "to":"+250788383383", "text":"☺ \"hi!\"", "from":"2020", "quick_replies":[] }`, + ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: "1: Unknown channel", ResponseStatus: 401, - RequestBody: `{ "to":"+250788383383", "text":"Error Message", "from":"2020", "quick_replies":[] }`, - Headers: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - SendPrep: setSendURL}, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: "1: Unknown channel", MockResponseStatus: 401, + ExpectedRequestBody: `{ "to":"+250788383383", "text":"Error Message", "from":"2020", "quick_replies":[] }`, + ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `0: Accepted for delivery`, ResponseStatus: 200, - RequestBody: `{ "to":"+250788383383", "text":"My pic!\nhttps://foo.bar/image.jpg", "from":"2020", "quick_replies":[] }`, - Headers: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: `0: Accepted for delivery`, MockResponseStatus: 200, + ExpectedRequestBody: `{ "to":"+250788383383", "text":"My pic!\nhttps://foo.bar/image.jpg", "from":"2020", "quick_replies":[] }`, + ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, + SendPrep: setSendURL}, {Label: "Send Quick Replies", - Text: "Some message", URN: "tel:+250788383383", QuickReplies: []string{"One", "Two", "Three"}, - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - RequestBody: `{ "to":"+250788383383", "text":"Some message", "from":"2020", "quick_replies":["One","Two","Three"] }`, - Headers: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - SendPrep: setSendURL}, + MsgText: "Some message", MsgURN: "tel:+250788383383", MsgQuickReplies: []string{"One", "Two", "Three"}, + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedRequestBody: `{ "to":"+250788383383", "text":"Some message", "from":"2020", "quick_replies":["One","Two","Three"] }`, + ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, + SendPrep: setSendURL}, } var jsonLongSendTestCases = []ChannelSendTestCase{ {Label: "Send Quick Replies", - Text: "This is a long message that will be longer than 30....... characters", URN: "tel:+250788383383", - QuickReplies: []string{"One", "Two", "Three"}, - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - RequestBody: `{ "to":"+250788383383", "text":"characters", "from":"2020", "quick_replies":["One","Two","Three"] }`, - Headers: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - SendPrep: setSendURL}, + MsgText: "This is a long message that will be longer than 30....... characters", MsgURN: "tel:+250788383383", + MsgQuickReplies: []string{"One", "Two", "Three"}, + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedRequestBody: `{ "to":"+250788383383", "text":"characters", "from":"2020", "quick_replies":["One","Two","Three"] }`, + ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, + SendPrep: setSendURL}, } var xmlSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - RequestBody: `+250788383383Simple Message2020`, - Headers: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedRequestBody: `+250788383383Simple Message2020`, + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: `☺`, URN: "tel:+250788383383", - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - RequestBody: `+2507883833832020`, - Headers: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, + MsgText: `☺`, MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedRequestBody: `+2507883833832020`, + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: "1: Unknown channel", ResponseStatus: 401, - RequestBody: `+250788383383Error Message2020`, - Headers: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: "1: Unknown channel", MockResponseStatus: 401, + ExpectedRequestBody: `+250788383383Error Message2020`, + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `0: Accepted for delivery`, ResponseStatus: 200, - RequestBody: `+250788383383My pic! https://foo.bar/image.jpg2020` + + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: `0: Accepted for delivery`, MockResponseStatus: 200, + ExpectedRequestBody: `+250788383383My pic! https://foo.bar/image.jpg2020` + ``, - Headers: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + SendPrep: setSendURL}, {Label: "Send Quick Replies", - Text: "Some message", URN: "tel:+250788383383", QuickReplies: []string{"One", "Two", "Three"}, - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - RequestBody: "+250788383383Some message2020" + + MsgText: "Some message", MsgURN: "tel:+250788383383", MsgQuickReplies: []string{"One", "Two", "Three"}, + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedRequestBody: "+250788383383Some message2020" + "OneTwoThree", - Headers: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + SendPrep: setSendURL}, } var xmlLongSendTestCases = []ChannelSendTestCase{ {Label: "Send Quick Replies", - Text: "This is a long message that will be longer than 30....... characters", URN: "tel:+250788383383", - QuickReplies: []string{"One", "Two", "Three"}, - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - RequestBody: "+250788383383characters2020" + + MsgText: "This is a long message that will be longer than 30....... characters", MsgURN: "tel:+250788383383", + MsgQuickReplies: []string{"One", "Two", "Three"}, + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedRequestBody: "+250788383383characters2020" + "OneTwoThree", - Headers: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + SendPrep: setSendURL}, } var xmlSendWithResponseContentTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "0", ResponseStatus: 200, - RequestBody: `+250788383383Simple Message2020`, - Headers: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0", MockResponseStatus: 200, + ExpectedRequestBody: `+250788383383Simple Message2020`, + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: `☺`, URN: "tel:+250788383383", - Status: "W", - ResponseBody: "0", ResponseStatus: 200, - RequestBody: `+2507883833832020`, - Headers: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, + MsgText: `☺`, MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0", MockResponseStatus: 200, + ExpectedRequestBody: `+2507883833832020`, + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: "0", ResponseStatus: 401, - RequestBody: `+250788383383Error Message2020`, - Headers: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: "0", MockResponseStatus: 401, + ExpectedRequestBody: `+250788383383Error Message2020`, + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + SendPrep: setSendURL}, {Label: "Error Sending with 200 status code", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: "1", ResponseStatus: 200, - RequestBody: `+250788383383Error Message2020`, - Headers: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: "1", MockResponseStatus: 200, + ExpectedRequestBody: `+250788383383Error Message2020`, + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `0`, ResponseStatus: 200, - RequestBody: `+250788383383My pic! https://foo.bar/image.jpg2020` + + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: `0`, MockResponseStatus: 200, + ExpectedRequestBody: `+250788383383My pic! https://foo.bar/image.jpg2020` + ``, - Headers: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + SendPrep: setSendURL}, {Label: "Send Quick Replies", - Text: "Some message", URN: "tel:+250788383383", QuickReplies: []string{"One", "Two", "Three"}, - Status: "W", - ResponseBody: "0", ResponseStatus: 200, - RequestBody: `+250788383383Some message2020` + + MsgText: "Some message", MsgURN: "tel:+250788383383", MsgQuickReplies: []string{"One", "Two", "Three"}, + ExpectedStatus: "W", + MockResponseBody: "0", MockResponseStatus: 200, + ExpectedRequestBody: `+250788383383Some message2020` + `OneTwoThree`, - Headers: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + SendPrep: setSendURL}, } var nationalGetSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - URLParams: map[string]string{"text": "Simple Message", "to": "788383383", "from": "2020"}, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "Simple Message", "to": "788383383", "from": "2020"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index 42f2ad648..d1fe9d2c5 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -562,66 +562,66 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "facebook:12345", - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "facebook:12345", + ExpectedStatus: "W", ExpectedExternalID: "mid.133", + MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, + SendPrep: setSendURL}, {Label: "Plain Response", - Text: "Simple Message", URN: "facebook:12345", - Status: "W", ExternalID: "mid.133", ResponseToExternalID: "23526", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"RESPONSE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "facebook:12345", + ExpectedStatus: "W", ExpectedExternalID: "mid.133", MsgResponseToExternalID: "23526", + MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"RESPONSE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, + SendPrep: setSendURL}, {Label: "Plain Send using ref URN", - Text: "Simple Message", URN: "facebook:ref:67890", - ContactURNs: map[string]bool{"facebook:12345": true, "ext:67890": true, "facebook:ref:67890": false}, - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133", "recipient_id": "12345"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"user_ref":"67890"},"message":{"text":"Simple Message"}}`, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "facebook:ref:67890", + ExpectedContactURNs: map[string]bool{"facebook:12345": true, "ext:67890": true, "facebook:ref:67890": false}, + ExpectedStatus: "W", ExpectedExternalID: "mid.133", + MockResponseBody: `{"message_id": "mid.133", "recipient_id": "12345"}`, MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"user_ref":"67890"},"message":{"text":"Simple Message"}}`, + SendPrep: setSendURL}, {Label: "Quick Reply", - Text: "Are you happy?", URN: "facebook:12345", QuickReplies: []string{"Yes", "No"}, - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"id":"12345"},"message":{"text":"Are you happy?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - SendPrep: setSendURL}, + MsgText: "Are you happy?", MsgURN: "facebook:12345", MsgQuickReplies: []string{"Yes", "No"}, + ExpectedStatus: "W", ExpectedExternalID: "mid.133", + MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"id":"12345"},"message":{"text":"Are you happy?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, + SendPrep: setSendURL}, {Label: "Long Message", - Text: "This is a long message which spans more than one part, what will actually be sent in the end if we exceed the max length?", - URN: "facebook:12345", QuickReplies: []string{"Yes", "No"}, Topic: "account", - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"ACCOUNT_UPDATE","recipient":{"id":"12345"},"message":{"text":"we exceed the max length?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - SendPrep: setSendURL}, + MsgText: "This is a long message which spans more than one part, what will actually be sent in the end if we exceed the max length?", + MsgURN: "facebook:12345", MsgQuickReplies: []string{"Yes", "No"}, MsgTopic: "account", + ExpectedStatus: "W", ExpectedExternalID: "mid.133", + MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"ACCOUNT_UPDATE","recipient":{"id":"12345"},"message":{"text":"we exceed the max length?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, + SendPrep: setSendURL}, {Label: "Send Photo", - URN: "facebook:12345", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"id":"12345"},"message":{"attachment":{"type":"image","payload":{"url":"https://foo.bar/image.jpg","is_reusable":true}}}}`, - SendPrep: setSendURL}, + MsgURN: "facebook:12345", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", ExpectedExternalID: "mid.133", + MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"id":"12345"},"message":{"attachment":{"type":"image","payload":{"url":"https://foo.bar/image.jpg","is_reusable":true}}}}`, + SendPrep: setSendURL}, {Label: "Send caption and photo with Quick Reply", - Text: "This is some text.", - URN: "facebook:12345", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - QuickReplies: []string{"Yes", "No"}, Topic: "event", - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"CONFIRMED_EVENT_UPDATE","recipient":{"id":"12345"},"message":{"text":"This is some text.","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - SendPrep: setSendURL}, + MsgText: "This is some text.", + MsgURN: "facebook:12345", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MsgQuickReplies: []string{"Yes", "No"}, MsgTopic: "event", + ExpectedStatus: "W", ExpectedExternalID: "mid.133", + MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"CONFIRMED_EVENT_UPDATE","recipient":{"id":"12345"},"message":{"text":"This is some text.","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, + SendPrep: setSendURL}, {Label: "Send Document", - URN: "facebook:12345", Attachments: []string{"application/pdf:https://foo.bar/document.pdf"}, - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"id":"12345"},"message":{"attachment":{"type":"file","payload":{"url":"https://foo.bar/document.pdf","is_reusable":true}}}}`, - SendPrep: setSendURL}, + MsgURN: "facebook:12345", MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, + ExpectedStatus: "W", ExpectedExternalID: "mid.133", + MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"id":"12345"},"message":{"attachment":{"type":"file","payload":{"url":"https://foo.bar/document.pdf","is_reusable":true}}}}`, + SendPrep: setSendURL}, {Label: "ID Error", - Text: "ID Error", URN: "facebook:12345", - Status: "E", - ResponseBody: `{ "is_error": true }`, ResponseStatus: 200, + MsgText: "ID Error", MsgURN: "facebook:12345", + ExpectedStatus: "E", + MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Error", - Text: "Error", URN: "facebook:12345", - Status: "E", - ResponseBody: `{ "is_error": true }`, ResponseStatus: 403, + MsgText: "Error", MsgURN: "facebook:12345", + ExpectedStatus: "E", + MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 403, SendPrep: setSendURL}, } diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index d30094da4..7da61ba27 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -372,341 +372,500 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var SendTestCasesFBA = []ChannelSendTestCase{ - {Label: "Plain Send", - Text: "Simple Message", URN: "facebook:12345", - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, - SendPrep: setSendURL}, - {Label: "Plain Response", - Text: "Simple Message", URN: "facebook:12345", - Status: "W", ExternalID: "mid.133", ResponseToExternalID: "23526", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"RESPONSE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, - SendPrep: setSendURL}, - {Label: "Plain Send using ref URN", - Text: "Simple Message", URN: "facebook:ref:67890", - ContactURNs: map[string]bool{"facebook:12345": true, "ext:67890": true, "facebook:ref:67890": false}, - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133", "recipient_id": "12345"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"UPDATE","recipient":{"user_ref":"67890"},"message":{"text":"Simple Message"}}`, - SendPrep: setSendURL}, - {Label: "Quick Reply", - Text: "Are you happy?", URN: "facebook:12345", QuickReplies: []string{"Yes", "No"}, - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"text":"Are you happy?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - SendPrep: setSendURL}, - {Label: "Long Message", - Text: "This is a long message which spans more than one part, what will actually be sent in the end if we exceed the max length?", - URN: "facebook:12345", QuickReplies: []string{"Yes", "No"}, Topic: "account", - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"ACCOUNT_UPDATE","recipient":{"id":"12345"},"message":{"text":"we exceed the max length?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - SendPrep: setSendURL}, - {Label: "Send Photo", - URN: "facebook:12345", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"attachment":{"type":"image","payload":{"url":"https://foo.bar/image.jpg","is_reusable":true}}}}`, - SendPrep: setSendURL}, - {Label: "Send caption and photo with Quick Reply", - Text: "This is some text.", - URN: "facebook:12345", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - QuickReplies: []string{"Yes", "No"}, Topic: "event", - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"CONFIRMED_EVENT_UPDATE","recipient":{"id":"12345"},"message":{"text":"This is some text.","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - SendPrep: setSendURL}, - {Label: "Send Document", - URN: "facebook:12345", Attachments: []string{"application/pdf:https://foo.bar/document.pdf"}, - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"attachment":{"type":"file","payload":{"url":"https://foo.bar/document.pdf","is_reusable":true}}}}`, - SendPrep: setSendURL}, - {Label: "ID Error", - Text: "ID Error", URN: "facebook:12345", - Status: "E", - ResponseBody: `{ "is_error": true }`, ResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Error", - Text: "Error", URN: "facebook:12345", - Status: "E", - ResponseBody: `{ "is_error": true }`, ResponseStatus: 403, - SendPrep: setSendURL}, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "facebook:12345", + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "Plain Response", + MsgText: "Simple Message", + MsgURN: "facebook:12345", + MsgResponseToExternalID: "23526", + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"RESPONSE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "Plain Send using ref URN", + MsgText: "Simple Message", + MsgURN: "facebook:ref:67890", + MockResponseBody: `{"message_id": "mid.133", "recipient_id": "12345"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"user_ref":"67890"},"message":{"text":"Simple Message"}}`, + ExpectedContactURNs: map[string]bool{"facebook:12345": true, "ext:67890": true, "facebook:ref:67890": false}, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "Quick Reply", + MsgText: "Are you happy?", + MsgURN: "facebook:12345", + MsgQuickReplies: []string{"Yes", "No"}, + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"text":"Are you happy?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "Long Message", + MsgText: "This is a long message which spans more than one part, what will actually be sent in the end if we exceed the max length?", + MsgURN: "facebook:12345", + MsgQuickReplies: []string{"Yes", "No"}, + MsgTopic: "account", + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"ACCOUNT_UPDATE","recipient":{"id":"12345"},"message":{"text":"we exceed the max length?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "Send Photo", + MsgURN: "facebook:12345", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"attachment":{"type":"image","payload":{"url":"https://foo.bar/image.jpg","is_reusable":true}}}}`, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "Send caption and photo with Quick Reply", + MsgText: "This is some text.", + MsgURN: "facebook:12345", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MsgQuickReplies: []string{"Yes", "No"}, + MsgTopic: "event", + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"CONFIRMED_EVENT_UPDATE","recipient":{"id":"12345"},"message":{"text":"This is some text.","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "Send Document", + MsgURN: "facebook:12345", + MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"attachment":{"type":"file","payload":{"url":"https://foo.bar/document.pdf","is_reusable":true}}}}`, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "ID Error", + MsgText: "ID Error", + MsgURN: "facebook:12345", + MockResponseBody: `{ "is_error": true }`, + MockResponseStatus: 200, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error", + MsgText: "Error", + MsgURN: "facebook:12345", + MockResponseBody: `{ "is_error": true }`, + MockResponseStatus: 403, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } var SendTestCasesIG = []ChannelSendTestCase{ - {Label: "Plain Send", - Text: "Simple Message", URN: "instagram:12345", - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, - SendPrep: setSendURL}, - {Label: "Plain Response", - Text: "Simple Message", URN: "instagram:12345", - Status: "W", ExternalID: "mid.133", ResponseToExternalID: "23526", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"RESPONSE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, - SendPrep: setSendURL}, - {Label: "Quick Reply", - Text: "Are you happy?", URN: "instagram:12345", QuickReplies: []string{"Yes", "No"}, - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"text":"Are you happy?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - SendPrep: setSendURL}, - {Label: "Long Message", - Text: "This is a long message which spans more than one part, what will actually be sent in the end if we exceed the max length?", - URN: "instagram:12345", QuickReplies: []string{"Yes", "No"}, Topic: "agent", - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"HUMAN_AGENT","recipient":{"id":"12345"},"message":{"text":"we exceed the max length?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - SendPrep: setSendURL}, - {Label: "Send Photo", - URN: "instagram:12345", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"attachment":{"type":"image","payload":{"url":"https://foo.bar/image.jpg","is_reusable":true}}}}`, - SendPrep: setSendURL}, - {Label: "Send caption and photo with Quick Reply", - Text: "This is some text.", - URN: "instagram:12345", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - QuickReplies: []string{"Yes", "No"}, - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"text":"This is some text.","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - SendPrep: setSendURL}, - {Label: "Tag Human Agent", - Text: "Simple Message", URN: "instagram:12345", - Status: "W", ExternalID: "mid.133", Topic: "agent", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"HUMAN_AGENT","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, - SendPrep: setSendURL}, - {Label: "Send Document", - URN: "instagram:12345", Attachments: []string{"application/pdf:https://foo.bar/document.pdf"}, - Status: "W", ExternalID: "mid.133", - ResponseBody: `{"message_id": "mid.133"}`, ResponseStatus: 200, - RequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"attachment":{"type":"file","payload":{"url":"https://foo.bar/document.pdf","is_reusable":true}}}}`, - SendPrep: setSendURL}, - {Label: "ID Error", - Text: "ID Error", URN: "instagram:12345", - Status: "E", - ResponseBody: `{ "is_error": true }`, ResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Error", - Text: "Error", URN: "instagram:12345", - Status: "E", - ResponseBody: `{ "is_error": true }`, ResponseStatus: 403, - SendPrep: setSendURL}, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "instagram:12345", + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "Plain Response", + MsgText: "Simple Message", + MsgURN: "instagram:12345", + MsgResponseToExternalID: "23526", + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"RESPONSE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "Quick Reply", + MsgText: "Are you happy?", + MsgURN: "instagram:12345", + MsgQuickReplies: []string{"Yes", "No"}, + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"text":"Are you happy?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "Long Message", + MsgText: "This is a long message which spans more than one part, what will actually be sent in the end if we exceed the max length?", + MsgURN: "instagram:12345", + MsgQuickReplies: []string{"Yes", "No"}, + MsgTopic: "agent", + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"HUMAN_AGENT","recipient":{"id":"12345"},"message":{"text":"we exceed the max length?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "Send Photo", + MsgURN: "instagram:12345", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"attachment":{"type":"image","payload":{"url":"https://foo.bar/image.jpg","is_reusable":true}}}}`, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL}, + { + Label: "Send caption and photo with Quick Reply", + MsgText: "This is some text.", + MsgURN: "instagram:12345", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MsgQuickReplies: []string{"Yes", "No"}, + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"text":"This is some text.","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL}, + { + Label: "Tag Human Agent", + MsgText: "Simple Message", + MsgURN: "instagram:12345", + MsgTopic: "agent", + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"HUMAN_AGENT","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL}, + { + Label: "Send Document", + MsgURN: "instagram:12345", + MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"attachment":{"type":"file","payload":{"url":"https://foo.bar/document.pdf","is_reusable":true}}}}`, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL}, + { + Label: "ID Error", + MsgText: "ID Error", + MsgURN: "instagram:12345", + MockResponseBody: `{ "is_error": true }`, + MockResponseStatus: 200, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error", + MsgText: "Error", + MsgURN: "instagram:12345", + MockResponseBody: `{ "is_error": true }`, + MockResponseStatus: 403, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } var SendTestCasesWAC = []ChannelSendTestCase{ - {Label: "Plain Send", - Text: "Simple Message", URN: "whatsapp:250788123123", Path: "/12345_ID/messages", - Status: "W", ExternalID: "157b5e14568e8", - ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"Simple Message","preview_url":false}}`, - SendPrep: setSendURL}, - {Label: "Unicode Send", - Text: "☺", URN: "whatsapp:250788123123", Path: "/12345_ID/messages", - Status: "W", ExternalID: "157b5e14568e8", - ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"☺","preview_url":false}}`, - SendPrep: setSendURL}, - {Label: "Audio Send", - Text: "audio caption", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"audio/mpeg:https://foo.bar/audio.mp3"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "whatsapp:250788123123", + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"Simple Message","preview_url":false}}`, + ExpectedRequestPath: "/12345_ID/messages", + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "whatsapp:250788123123", + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"☺","preview_url":false}}`, + ExpectedRequestPath: "/12345_ID/messages", + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Audio Send", + MsgText: "audio caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"audio/mpeg:https://foo.bar/audio.mp3"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"audio","audio":{"link":"https://foo.bar/audio.mp3"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, - MockedRequest{ + { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"audio caption","preview_url":false}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL}, - {Label: "Document Send", - Text: "document caption", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"application/pdf:https://foo.bar/document.pdf"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Document Send", + MsgText: "document caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"document","document":{"link":"https://foo.bar/document.pdf"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, - MockedRequest{ + { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"document caption","preview_url":false}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL}, - - {Label: "Image Send", - Text: "document caption", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Image Send", + MsgText: "document caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, - MockedRequest{ + { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"document caption","preview_url":false}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL}, - {Label: "Video Send", - Text: "video caption", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"video/mp4:https://foo.bar/video.mp4"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Video Send", + MsgText: "video caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"video","video":{"link":"https://foo.bar/video.mp4"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, - MockedRequest{ + { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"video caption","preview_url":false}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL}, - - {Label: "Template Send", - Text: "templated message", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Metadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "language": "eng", "variables": ["Chef", "tomorrow"]}}`), - ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 200, - RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"template","template":{"name":"revive_issue","language":{"policy":"deterministic","code":"en"},"components":[{"type":"body","sub_type":"","index":"","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - - {Label: "Template Country Language", - Text: "templated message", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Metadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "language": "eng", "country": "US", "variables": ["Chef", "tomorrow"]}}`), - ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 200, - RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"template","template":{"name":"revive_issue","language":{"policy":"deterministic","code":"en_US"},"components":[{"type":"body","sub_type":"","index":"","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, - SendPrep: setSendURL, + { + Label: "Template Send", + MsgText: "templated message", + MsgURN: "whatsapp:250788123123", + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + MsgMetadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "language": "eng", "variables": ["Chef", "tomorrow"]}}`), + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"template","template":{"name":"revive_issue","language":{"policy":"deterministic","code":"en"},"components":[{"type":"body","sub_type":"","index":"","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, + SendPrep: setSendURL, + }, + { + Label: "Template Country Language", + MsgText: "templated message", + MsgURN: "whatsapp:250788123123", + MsgMetadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "language": "eng", "country": "US", "variables": ["Chef", "tomorrow"]}}`), + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"template","template":{"name":"revive_issue","language":{"policy":"deterministic","code":"en_US"},"components":[{"type":"body","sub_type":"","index":"","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - {Label: "Template Invalid Language", - Text: "templated message", URN: "whatsapp:250788123123", - Error: `unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, - Metadata: json.RawMessage(`{"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}}`), + { + Label: "Template Invalid Language", + MsgText: "templated message", + MsgURN: "whatsapp:250788123123", + MsgMetadata: json.RawMessage(`{"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}}`), + ExpectedError: `unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, }, - {Label: "Interactive Button Message Send", - Text: "Interactive Button Msg", URN: "whatsapp:250788123123", QuickReplies: []string{"BUTTON1"}, - Status: "W", ExternalID: "157b5e14568e8", - ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, - SendPrep: setSendURL}, - {Label: "Interactive List Message Send", - Text: "Interactive List Msg", URN: "whatsapp:250788123123", QuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4"}, - Status: "W", ExternalID: "157b5e14568e8", - ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, - SendPrep: setSendURL}, - {Label: "Interactive Button Message Send with attachment", - Text: "Interactive Button Msg", URN: "whatsapp:250788123123", QuickReplies: []string{"BUTTON1"}, - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "Interactive Button Message Send", + MsgText: "Interactive Button Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"BUTTON1"}, + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Interactive List Message Send", + MsgText: "Interactive List Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4"}, + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Interactive Button Message Send with attachment", + MsgText: "Interactive Button Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"BUTTON1"}, + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, - MockedRequest{ + { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL}, - {Label: "Interactive List Message Send with attachment", - Text: "Interactive List Msg", URN: "whatsapp:250788123123", QuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4"}, - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Interactive List Message Send with attachment", + MsgText: "Interactive List Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4"}, + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, - MockedRequest{ + { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL}, - {Label: "Link Sending", - Text: "Link Sending https://link.com", URN: "whatsapp:250788123123", Path: "/12345_ID/messages", - Status: "W", ExternalID: "157b5e14568e8", - ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"Link Sending https://link.com","preview_url":true}}`, - SendPrep: setSendURL}, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Link Sending", + MsgText: "Link Sending https://link.com", + MsgURN: "whatsapp:250788123123", + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"Link Sending https://link.com","preview_url":true}}`, + ExpectedRequestPath: "/12345_ID/messages", + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { // shorter max msg length for testing maxMsgLength = 100 + var ChannelFBA = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "FBA", "12345", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}) var ChannelIG = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "IG", "12345", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}) var ChannelWAC = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WAC", "12345_ID", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}) + RunChannelSendTestCases(t, ChannelFBA, newHandler("FBA", "Facebook", false), SendTestCasesFBA, nil) RunChannelSendTestCases(t, ChannelIG, newHandler("IG", "Instagram", false), SendTestCasesIG, nil) RunChannelSendTestCases(t, ChannelWAC, newHandler("WAC", "Cloud API WhatsApp", false), SendTestCasesWAC, nil) diff --git a/handlers/firebase/firebase_test.go b/handlers/firebase/firebase_test.go index 3d4498602..752ef020f 100644 --- a/handlers/firebase/firebase_test.go +++ b/handlers/firebase/firebase_test.go @@ -73,51 +73,51 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var notificationSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "fcm:250788123123", URNAuth: "auth1", - Status: "W", ExternalID: "123456", - ResponseBody: `{"success":1, "multicast_id": 123456}`, ResponseStatus: 200, - Headers: map[string]string{"Authorization": "key=FCMKey"}, - RequestBody: `{"data":{"type":"rapidpro","title":"FCMTitle","message":"Simple Message","message_id":10,"session_status":""},"notification":{"title":"FCMTitle","body":"Simple Message"},"content_available":true,"to":"auth1","priority":"high"}`, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "fcm:250788123123", MsgURNAuth: "auth1", + ExpectedStatus: "W", ExpectedExternalID: "123456", + MockResponseBody: `{"success":1, "multicast_id": 123456}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Authorization": "key=FCMKey"}, + ExpectedRequestBody: `{"data":{"type":"rapidpro","title":"FCMTitle","message":"Simple Message","message_id":10,"session_status":""},"notification":{"title":"FCMTitle","body":"Simple Message"},"content_available":true,"to":"auth1","priority":"high"}`, + SendPrep: setSendURL}, } var sendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "fcm:250788123123", URNAuth: "auth1", - Status: "W", ExternalID: "123456", - ResponseBody: `{"success":1, "multicast_id": 123456}`, ResponseStatus: 200, - Headers: map[string]string{"Authorization": "key=FCMKey"}, - RequestBody: `{"data":{"type":"rapidpro","title":"FCMTitle","message":"Simple Message","message_id":10,"session_status":""},"content_available":false,"to":"auth1","priority":"high"}`, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "fcm:250788123123", MsgURNAuth: "auth1", + ExpectedStatus: "W", ExpectedExternalID: "123456", + MockResponseBody: `{"success":1, "multicast_id": 123456}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Authorization": "key=FCMKey"}, + ExpectedRequestBody: `{"data":{"type":"rapidpro","title":"FCMTitle","message":"Simple Message","message_id":10,"session_status":""},"content_available":false,"to":"auth1","priority":"high"}`, + SendPrep: setSendURL}, {Label: "Long Message", - Text: longMsg, - URN: "fcm:250788123123", URNAuth: "auth1", - Status: "W", ExternalID: "123456", - ResponseBody: `{"success":1, "multicast_id": 123456}`, ResponseStatus: 200, - Headers: map[string]string{"Authorization": "key=FCMKey"}, - RequestBody: `{"data":{"type":"rapidpro","title":"FCMTitle","message":"ate ac.","message_id":10,"session_status":""},"content_available":false,"to":"auth1","priority":"high"}`, - SendPrep: setSendURL}, + MsgText: longMsg, + MsgURN: "fcm:250788123123", MsgURNAuth: "auth1", + ExpectedStatus: "W", ExpectedExternalID: "123456", + MockResponseBody: `{"success":1, "multicast_id": 123456}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Authorization": "key=FCMKey"}, + ExpectedRequestBody: `{"data":{"type":"rapidpro","title":"FCMTitle","message":"ate ac.","message_id":10,"session_status":""},"content_available":false,"to":"auth1","priority":"high"}`, + SendPrep: setSendURL}, {Label: "Quick Reply", - Text: "Simple Message", URN: "fcm:250788123123", URNAuth: "auth1", QuickReplies: []string{"yes", "no"}, Attachments: []string{"image/jpeg:https://foo.bar"}, - Status: "W", ExternalID: "123456", - ResponseBody: `{"success":1, "multicast_id": 123456}`, ResponseStatus: 200, - Headers: map[string]string{"Authorization": "key=FCMKey"}, - RequestBody: `{"data":{"type":"rapidpro","title":"FCMTitle","message":"Simple Message\nhttps://foo.bar","message_id":10,"session_status":"","quick_replies":["yes","no"]},"content_available":false,"to":"auth1","priority":"high"}`, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "fcm:250788123123", MsgURNAuth: "auth1", MsgQuickReplies: []string{"yes", "no"}, MsgAttachments: []string{"image/jpeg:https://foo.bar"}, + ExpectedStatus: "W", ExpectedExternalID: "123456", + MockResponseBody: `{"success":1, "multicast_id": 123456}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Authorization": "key=FCMKey"}, + ExpectedRequestBody: `{"data":{"type":"rapidpro","title":"FCMTitle","message":"Simple Message\nhttps://foo.bar","message_id":10,"session_status":"","quick_replies":["yes","no"]},"content_available":false,"to":"auth1","priority":"high"}`, + SendPrep: setSendURL}, {Label: "Error", - Text: "Error", URN: "fcm:250788123123", URNAuth: "auth1", - Status: "E", - ResponseBody: `{ "success": 0 }`, ResponseStatus: 200, + MsgText: "Error", MsgURN: "fcm:250788123123", MsgURNAuth: "auth1", + ExpectedStatus: "E", + MockResponseBody: `{ "success": 0 }`, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "No Multicast ID", - Text: "Error", URN: "fcm:250788123123", URNAuth: "auth1", - Status: "E", - ResponseBody: `{ "success": 1 }`, ResponseStatus: 200, + MsgText: "Error", MsgURN: "fcm:250788123123", MsgURNAuth: "auth1", + ExpectedStatus: "E", + MockResponseBody: `{ "success": 1 }`, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Request Error", - Text: "Error", URN: "fcm:250788123123", URNAuth: "auth1", - Status: "E", - ResponseBody: `{ "success": 0 }`, ResponseStatus: 500, + MsgText: "Error", MsgURN: "fcm:250788123123", MsgURNAuth: "auth1", + ExpectedStatus: "E", + MockResponseBody: `{ "success": 0 }`, MockResponseStatus: 500, SendPrep: setSendURL}, } diff --git a/handlers/freshchat/freshchat_test.go b/handlers/freshchat/freshchat_test.go index b4a82265a..e27322753 100644 --- a/handlers/freshchat/freshchat_test.go +++ b/handlers/freshchat/freshchat_test.go @@ -74,47 +74,47 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", - URN: "freshchat:0534f78-b6e9-4f79-8853-11cedfc1f35b/c8fddfaf-622a-4a0e-b060-4f3ccbeab606", - Status: "W", - ExternalID: "", - ResponseBody: "", - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message ☺", + MsgURN: "freshchat:0534f78-b6e9-4f79-8853-11cedfc1f35b/c8fddfaf-622a-4a0e-b060-4f3ccbeab606", + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseBody: "", + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Authorization": "Bearer enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", }, - RequestBody: `{"messages":[{"message_parts":[{"text":{"content":"Simple Message ☺"}}],"actor_id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606","actor_type":"agent"}],"channel_id":"0534f78-b6e9-4f79-8853-11cedfc1f35b","users":[{"id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606"}]}`, - SendPrep: setSendURL, + ExpectedRequestBody: `{"messages":[{"message_parts":[{"text":{"content":"Simple Message ☺"}}],"actor_id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606","actor_type":"agent"}],"channel_id":"0534f78-b6e9-4f79-8853-11cedfc1f35b","users":[{"id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606"}]}`, + SendPrep: setSendURL, }, {Label: "Send with text and image", - Text: "Simple Message ☺", - URN: "freshchat:0534f78-b6e9-4f79-8853-11cedfc1f35b/c8fddfaf-622a-4a0e-b060-4f3ccbeab606", - Status: "W", - ExternalID: "", - ResponseBody: "", - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message ☺", + MsgURN: "freshchat:0534f78-b6e9-4f79-8853-11cedfc1f35b/c8fddfaf-622a-4a0e-b060-4f3ccbeab606", + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseBody: "", + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Authorization": "Bearer enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", }, - Attachments: []string{"image:https://foo.bar/image.jpg"}, - RequestBody: `{"messages":[{"message_parts":[{"text":{"content":"Simple Message ☺"}},{"image":{"url":"https://foo.bar/image.jpg"}}],"actor_id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606","actor_type":"agent"}],"channel_id":"0534f78-b6e9-4f79-8853-11cedfc1f35b","users":[{"id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606"}]}`, - SendPrep: setSendURL, + MsgAttachments: []string{"image:https://foo.bar/image.jpg"}, + ExpectedRequestBody: `{"messages":[{"message_parts":[{"text":{"content":"Simple Message ☺"}},{"image":{"url":"https://foo.bar/image.jpg"}}],"actor_id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606","actor_type":"agent"}],"channel_id":"0534f78-b6e9-4f79-8853-11cedfc1f35b","users":[{"id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606"}]}`, + SendPrep: setSendURL, }, {Label: "Send with image only", - URN: "freshchat:0534f78-b6e9-4f79-8853-11cedfc1f35b/c8fddfaf-622a-4a0e-b060-4f3ccbeab606", - Status: "W", - ExternalID: "", - ResponseBody: "", - ResponseStatus: 200, - Headers: map[string]string{ + MsgURN: "freshchat:0534f78-b6e9-4f79-8853-11cedfc1f35b/c8fddfaf-622a-4a0e-b060-4f3ccbeab606", + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseBody: "", + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Authorization": "Bearer enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", }, - Attachments: []string{"image/jpg:https://foo.bar/image.jpg"}, - RequestBody: `{"messages":[{"message_parts":[{"image":{"url":"https://foo.bar/image.jpg"}}],"actor_id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606","actor_type":"agent"}],"channel_id":"0534f78-b6e9-4f79-8853-11cedfc1f35b","users":[{"id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606"}]}`, - SendPrep: setSendURL, + MsgAttachments: []string{"image/jpg:https://foo.bar/image.jpg"}, + ExpectedRequestBody: `{"messages":[{"message_parts":[{"image":{"url":"https://foo.bar/image.jpg"}}],"actor_id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606","actor_type":"agent"}],"channel_id":"0534f78-b6e9-4f79-8853-11cedfc1f35b","users":[{"id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606"}]}`, + SendPrep: setSendURL, }, } diff --git a/handlers/globe/globe_test.go b/handlers/globe/globe_test.go index c50cd3136..5da95b16c 100644 --- a/handlers/globe/globe_test.go +++ b/handlers/globe/globe_test.go @@ -135,27 +135,27 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var sendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - ResponseBody: `[{"Response": "0"}]`, ResponseStatus: 200, - RequestBody: `{"address":"250788383383","message":"Simple Message","passphrase":"opensesame","app_id":"12345","app_secret":"mysecret"}`, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, + ExpectedRequestBody: `{"address":"250788383383","message":"Simple Message","passphrase":"opensesame","app_id":"12345","app_secret":"mysecret"}`, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "tel:+250788383383", - Status: "W", - ResponseBody: `[{"Response": "0"}]`, ResponseStatus: 200, - RequestBody: `{"address":"250788383383","message":"☺","passphrase":"opensesame","app_id":"12345","app_secret":"mysecret"}`, - SendPrep: setSendURL}, + MsgText: "☺", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, + ExpectedRequestBody: `{"address":"250788383383","message":"☺","passphrase":"opensesame","app_id":"12345","app_secret":"mysecret"}`, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `[{"Response": "0"}]`, ResponseStatus: 200, - RequestBody: `{"address":"250788383383","message":"My pic!\nhttps://foo.bar/image.jpg","passphrase":"opensesame","app_id":"12345","app_secret":"mysecret"}`, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, + ExpectedRequestBody: `{"address":"250788383383","message":"My pic!\nhttps://foo.bar/image.jpg","passphrase":"opensesame","app_id":"12345","app_secret":"mysecret"}`, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Sending", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `[{"Response": "101"}]`, ResponseStatus: 403, + MsgText: "Error Sending", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `[{"Response": "101"}]`, MockResponseStatus: 403, SendPrep: setSendURL}, } diff --git a/handlers/highconnection/highconnection_test.go b/handlers/highconnection/highconnection_test.go index 8a6d90897..2492f6220 100644 --- a/handlers/highconnection/highconnection_test.go +++ b/handlers/highconnection/highconnection_test.go @@ -54,11 +54,11 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", - URN: "tel:+250788383383", - Status: "W", - Flow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, - URLParams: map[string]string{ + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, + ExpectedURLParams: map[string]string{ "accountid": "Username", "password": "Password", "text": "Simple Message", @@ -69,13 +69,13 @@ var defaultSendTestCases = []ChannelSendTestCase{ "ret_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status", "ret_mo_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive", }, - ResponseStatus: 200, - SendPrep: setSendURL}, + MockResponseStatus: 200, + SendPrep: setSendURL}, {Label: "Plain Send without flow", - Text: "Simple Message", - URN: "tel:+250788383383", - Status: "W", - URLParams: map[string]string{ + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedURLParams: map[string]string{ "accountid": "Username", "password": "Password", "text": "Simple Message", @@ -86,14 +86,14 @@ var defaultSendTestCases = []ChannelSendTestCase{ "ret_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status", "ret_mo_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive", }, - ResponseStatus: 200, - SendPrep: setSendURL}, + MockResponseStatus: 200, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", - URN: "tel:+250788383383", - Status: "W", - Flow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, - URLParams: map[string]string{ + MsgText: "☺", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, + ExpectedURLParams: map[string]string{ "accountid": "Username", "password": "Password", "text": "☺", @@ -104,14 +104,14 @@ var defaultSendTestCases = []ChannelSendTestCase{ "ret_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status", "ret_mo_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive", }, - ResponseStatus: 200, - SendPrep: setSendURL}, + MockResponseStatus: 200, + SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+250788383383", - Status: "W", - Flow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, - URLParams: map[string]string{ + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, + ExpectedURLParams: map[string]string{ "accountid": "Username", "password": "Password", "text": "I need to keep adding more things to make it work", @@ -122,15 +122,15 @@ var defaultSendTestCases = []ChannelSendTestCase{ "ret_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status", "ret_mo_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive", }, - ResponseStatus: 200, - SendPrep: setSendURL}, + MockResponseStatus: 200, + SendPrep: setSendURL}, {Label: "Send Attachement", - Text: "My pic!", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - URN: "tel:+250788383383", - Status: "W", - Flow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, - URLParams: map[string]string{ + MsgText: "My pic!", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, + ExpectedURLParams: map[string]string{ "accountid": "Username", "password": "Password", "text": "My pic!\nhttps://foo.bar/image.jpg", @@ -141,14 +141,14 @@ var defaultSendTestCases = []ChannelSendTestCase{ "ret_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status", "ret_mo_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive", }, - ResponseStatus: 200, - SendPrep: setSendURL}, + MockResponseStatus: 200, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Sending", URN: "tel:+250788383383", - Status: "E", - ResponseStatus: 403, - SendPrep: setSendURL}, + MsgText: "Error Sending", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseStatus: 403, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/hormuud/hormuud_test.go b/handlers/hormuud/hormuud_test.go index 171b36375..9a38efb9f 100644 --- a/handlers/hormuud/hormuud_test.go +++ b/handlers/hormuud/hormuud_test.go @@ -47,35 +47,35 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var sendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", ExternalID: "msg1", - ResponseBody: `{"ResCode": "res", "ResMsg": "msg", "Data": { "MessageID": "msg1", "Description": "accepted" } }`, ResponseStatus: 200, - RequestBody: `{"mobile":"250788383383","message":"Simple Message","senderid":"2020","mType":-1,"eType":-1,"UDH":""}`, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", ExpectedExternalID: "msg1", + MockResponseBody: `{"ResCode": "res", "ResMsg": "msg", "Data": { "MessageID": "msg1", "Description": "accepted" } }`, MockResponseStatus: 200, + ExpectedRequestBody: `{"mobile":"250788383383","message":"Simple Message","senderid":"2020","mType":-1,"eType":-1,"UDH":""}`, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "tel:+250788383383", - Status: "W", ExternalID: "msg1", - ResponseBody: `{"ResCode": "res", "ResMsg": "msg", "Data": { "MessageID": "msg1", "Description": "accepted" } }`, ResponseStatus: 200, - RequestBody: `{"mobile":"250788383383","message":"☺","senderid":"2020","mType":-1,"eType":-1,"UDH":""}`, - SendPrep: setSendURL}, + MsgText: "☺", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", ExpectedExternalID: "msg1", + MockResponseBody: `{"ResCode": "res", "ResMsg": "msg", "Data": { "MessageID": "msg1", "Description": "accepted" } }`, MockResponseStatus: 200, + ExpectedRequestBody: `{"mobile":"250788383383","message":"☺","senderid":"2020","mType":-1,"eType":-1,"UDH":""}`, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", ExternalID: "msg1", - ResponseBody: `{"ResCode": "res", "ResMsg": "msg", "Data": { "MessageID": "msg1", "Description": "accepted" } }`, ResponseStatus: 200, - RequestBody: `{"mobile":"250788383383","message":"My pic!\nhttps://foo.bar/image.jpg","senderid":"2020","mType":-1,"eType":-1,"UDH":""}`, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", ExpectedExternalID: "msg1", + MockResponseBody: `{"ResCode": "res", "ResMsg": "msg", "Data": { "MessageID": "msg1", "Description": "accepted" } }`, MockResponseStatus: 200, + ExpectedRequestBody: `{"mobile":"250788383383","message":"My pic!\nhttps://foo.bar/image.jpg","senderid":"2020","mType":-1,"eType":-1,"UDH":""}`, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Sending", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `[{"Response": "101"}]`, ResponseStatus: 403, + MsgText: "Error Sending", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `[{"Response": "101"}]`, MockResponseStatus: 403, SendPrep: setSendURL}, } var tokenTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "E", - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/i2sms/i2sms_test.go b/handlers/i2sms/i2sms_test.go index 167038ce3..0641b4c79 100644 --- a/handlers/i2sms/i2sms_test.go +++ b/handlers/i2sms/i2sms_test.go @@ -39,10 +39,10 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", ExternalID: "5b8fc97d58795484819426", - ResponseBody: `{"result":{"session_id":"5b8fc97d58795484819426"}, "error_code": "00", "error_desc": "Success"}`, ResponseStatus: 200, - PostParams: map[string]string{ + MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", ExpectedExternalID: "5b8fc97d58795484819426", + MockResponseBody: `{"result":{"session_id":"5b8fc97d58795484819426"}, "error_code": "00", "error_desc": "Success"}`, MockResponseStatus: 200, + ExpectedPostParams: map[string]string{ "action": "send_single", "mobile": "250788383383", "message": "Simple Message ☺\nhttps://foo.bar/image.jpg", @@ -50,19 +50,19 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Invalid JSON", - Text: "Invalid XML", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `not json`, ResponseStatus: 200, + MsgText: "Invalid XML", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `not json`, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Error Response", - Text: "Error Response", URN: "tel:+250788383383", - Status: "F", - ResponseBody: `{"result":{}, "error_code": "10", "error_desc": "Failed"}`, ResponseStatus: 200, + MsgText: "Error Response", MsgURN: "tel:+250788383383", + ExpectedStatus: "F", + MockResponseBody: `{"result":{}, "error_code": "10", "error_desc": "Failed"}`, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `Bad Gateway`, ResponseStatus: 501, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `Bad Gateway`, MockResponseStatus: 501, SendPrep: setSendURL}, } diff --git a/handlers/infobip/infobip_test.go b/handlers/infobip/infobip_test.go index c5f7450b1..2c3503f6d 100644 --- a/handlers/infobip/infobip_test.go +++ b/handlers/infobip/infobip_test.go @@ -220,74 +220,74 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", ExternalID: "12345", - ResponseBody: `{"messages":[{"status":{"groupId": 1}, "messageId": "12345"}}`, ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", ExpectedExternalID: "12345", + MockResponseBody: `{"messages":[{"status":{"groupId": 1}, "messageId": "12345"}}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, - RequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Simple Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Simple Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "tel:+250788383383", - Status: "W", - ResponseBody: `{"messages":[{"status":{"groupId": 1}}}`, ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "☺", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: `{"messages":[{"status":{"groupId": 1}}}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, - RequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"☺","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"☺","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `{"messages":[{"status":{"groupId": 1}}}`, ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: `{"messages":[{"status":{"groupId": 1}}}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, - RequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"My pic!\nhttps://foo.bar/image.jpg","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"My pic!\nhttps://foo.bar/image.jpg","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "failed" }`, ResponseStatus: 401, - Headers: map[string]string{ + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, - RequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Error Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Error Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, + SendPrep: setSendURL}, {Label: "Error groupId", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{"messages":[{"status":{"groupId": 2}}}`, ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{"messages":[{"status":{"groupId": 2}}}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, - RequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Simple Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Simple Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, + SendPrep: setSendURL}, } var transSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", ExternalID: "12345", - ResponseBody: `{"messages":[{"status":{"groupId": 1}, "messageId": "12345"}}`, ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", ExpectedExternalID: "12345", + MockResponseBody: `{"messages":[{"status":{"groupId": 1}, "messageId": "12345"}}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, - RequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Simple Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered","transliteration":"COLOMBIAN"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Simple Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered","transliteration":"COLOMBIAN"}]}`, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/jasmin/jasmin_test.go b/handlers/jasmin/jasmin_test.go index c00ea12c6..49a1d673b 100644 --- a/handlers/jasmin/jasmin_test.go +++ b/handlers/jasmin/jasmin_test.go @@ -57,37 +57,37 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - ResponseBody: `Success "External ID1"`, ResponseStatus: 200, ExternalID: "External ID1", - URLParams: map[string]string{"content": "Simple Message", "to": "250788383383", "coding": "0", + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: `Success "External ID1"`, MockResponseStatus: 200, ExpectedExternalID: "External ID1", + ExpectedURLParams: map[string]string{"content": "Simple Message", "to": "250788383383", "coding": "0", "dlr-level": "2", "dlr": "yes", "dlr-method": http.MethodPost, "username": "Username", "password": "Password", "dlr-url": "https://localhost/c/js/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status"}, SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", - Status: "W", - ResponseBody: `Success "External ID1"`, ResponseStatus: 200, - URLParams: map[string]string{"content": "?"}, - SendPrep: setSendURL}, + MsgText: "☺", + ExpectedStatus: "W", + MockResponseBody: `Success "External ID1"`, MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"content": "?"}, + SendPrep: setSendURL}, {Label: "Smart Encoding", - Text: "Fancy “Smart” Quotes", URN: "tel:+250788383383", HighPriority: false, - Status: "W", - ResponseBody: `Success "External ID1"`, ResponseStatus: 200, - URLParams: map[string]string{"content": `Fancy "Smart" Quotes`}, - SendPrep: setSendURL}, + MsgText: "Fancy “Smart” Quotes", MsgURN: "tel:+250788383383", MsgHighPriority: false, + ExpectedStatus: "W", + MockResponseBody: `Success "External ID1"`, MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"content": `Fancy "Smart" Quotes`}, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", HighPriority: true, Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `Success "External ID1"`, ResponseStatus: 200, - URLParams: map[string]string{"content": "My pic!\nhttps://foo.bar/image.jpg"}, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgHighPriority: true, MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: `Success "External ID1"`, MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"content": "My pic!\nhttps://foo.bar/image.jpg"}, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", HighPriority: false, - Status: "E", - ResponseBody: "Failed Sending", ResponseStatus: 401, - URLParams: map[string]string{"content": `Error Message`}, - SendPrep: setSendURL}, + MsgText: "Error Message", MsgURN: "tel:+250788383383", MsgHighPriority: false, + ExpectedStatus: "E", + MockResponseBody: "Failed Sending", MockResponseStatus: 401, + ExpectedURLParams: map[string]string{"content": `Error Message`}, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index 6f67cfa6f..e39f25116 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -325,52 +325,52 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", - URN: "jiochat:12345", - Status: "W", - ExternalID: "", - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message ☺", + MsgURN: "jiochat:12345", + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer ACCESS_TOKEN", }, - RequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"Simple Message ☺"}}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"Simple Message ☺"}}`, + SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "jiochat:12345", - Status: "W", - ExternalID: "", - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "jiochat:12345", + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer ACCESS_TOKEN", }, - RequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"I need to keep adding more things to make it work"}}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"I need to keep adding more things to make it work"}}`, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", - URN: "jiochat:12345", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ExternalID: "", - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "My pic!", + MsgURN: "jiochat:12345", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer ACCESS_TOKEN", }, - RequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"My pic!\nhttps://foo.bar/image.jpg"}}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"My pic!\nhttps://foo.bar/image.jpg"}}`, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", - URN: "jiochat:12345", - Status: "E", - ResponseStatus: 401, - Error: "received non 200 status: 401", - SendPrep: setSendURL}, + MsgText: "Error Message", + MsgURN: "jiochat:12345", + ExpectedStatus: "E", + MockResponseStatus: 401, + ExpectedError: "received non 200 status: 401", + SendPrep: setSendURL}, } func setupBackend(mb *courier.MockBackend) { diff --git a/handlers/junebug/junebug_test.go b/handlers/junebug/junebug_test.go index a7d0d873b..0e65179d5 100644 --- a/handlers/junebug/junebug_test.go +++ b/handlers/junebug/junebug_test.go @@ -147,55 +147,55 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var sendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", - URN: "tel:+250788383383", - Status: "W", - ExternalID: "externalID", - Headers: map[string]string{"Authorization": "Basic dXNlcjE6cGFzczE="}, - RequestBody: `{"event_url":"https://localhost/c/jn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/event","content":"Simple Message","from":"2020","to":"+250788383383"}`, - ResponseBody: `{"result":{"message_id":"externalID"}}`, - ResponseStatus: 200, - SendPrep: setSendURL}, + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "externalID", + ExpectedHeaders: map[string]string{"Authorization": "Basic dXNlcjE6cGFzczE="}, + ExpectedRequestBody: `{"event_url":"https://localhost/c/jn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/event","content":"Simple Message","from":"2020","to":"+250788383383"}`, + MockResponseBody: `{"result":{"message_id":"externalID"}}`, + MockResponseStatus: 200, + SendPrep: setSendURL}, {Label: "Send Attachement", - Text: "My pic!", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - URN: "tel:+250788383383", - Status: "W", - ExternalID: "externalID", - RequestBody: `{"event_url":"https://localhost/c/jn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/event","content":"My pic!\nhttps://foo.bar/image.jpg","from":"2020","to":"+250788383383"}`, - ResponseBody: `{"result":{"message_id":"externalID"}}`, - ResponseStatus: 200, - SendPrep: setSendURL}, + MsgText: "My pic!", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "externalID", + ExpectedRequestBody: `{"event_url":"https://localhost/c/jn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/event","content":"My pic!\nhttps://foo.bar/image.jpg","from":"2020","to":"+250788383383"}`, + MockResponseBody: `{"result":{"message_id":"externalID"}}`, + MockResponseStatus: 200, + SendPrep: setSendURL}, {Label: "Invalid JSON Response", - Text: "Error Sending", URN: "tel:+250788383383", - Status: "E", - ResponseStatus: 200, - ResponseBody: "not json", - SendPrep: setSendURL}, + MsgText: "Error Sending", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseStatus: 200, + MockResponseBody: "not json", + SendPrep: setSendURL}, {Label: "Missing External ID", - Text: "Error Sending", URN: "tel:+250788383383", - Status: "E", - ResponseStatus: 200, - ResponseBody: "{}", - SendPrep: setSendURL}, + MsgText: "Error Sending", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseStatus: 200, + MockResponseBody: "{}", + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Sending", URN: "tel:+250788383383", - Status: "E", - ResponseStatus: 403, - SendPrep: setSendURL}, + MsgText: "Error Sending", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseStatus: 403, + SendPrep: setSendURL}, } var authenticatedSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", - URN: "tel:+250788383383", - Status: "W", - ExternalID: "externalID", - Headers: map[string]string{"Authorization": "Basic dXNlcjE6cGFzczE="}, - RequestBody: `{"event_url":"https://localhost/c/jn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/event","content":"Simple Message","from":"2020","to":"+250788383383","event_auth_token":"sesame"}`, - ResponseBody: `{"result":{"message_id":"externalID"}}`, - ResponseStatus: 200, - SendPrep: setSendURL}, + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "externalID", + ExpectedHeaders: map[string]string{"Authorization": "Basic dXNlcjE6cGFzczE="}, + ExpectedRequestBody: `{"event_url":"https://localhost/c/jn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/event","content":"Simple Message","from":"2020","to":"+250788383383","event_auth_token":"sesame"}`, + MockResponseBody: `{"result":{"message_id":"externalID"}}`, + MockResponseStatus: 200, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/kaleyra/kaleyra_test.go b/handlers/kaleyra/kaleyra_test.go index 34d31dbcb..b30ad53ed 100644 --- a/handlers/kaleyra/kaleyra_test.go +++ b/handlers/kaleyra/kaleyra_test.go @@ -117,64 +117,64 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var sendTestCases = []ChannelSendTestCase{ { - Label: "Plain Send", - Text: "Simple Message", - URN: "whatsapp:14133881111", - Status: "W", - ExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", - Path: "/v1/SID/messages", - Headers: map[string]string{"Content-type": "application/x-www-form-urlencoded"}, - RequestBody: "api-key=123456&body=Simple+Message&callback_url=https%3A%2F%2Flocalhost%2Fc%2Fkwa%2F8eb23e93-5ecb-45ba-b726-3b064e0c568c%2Fstatus&channel=WhatsApp&from=250788383383&to=14133881111&type=text", - ResponseStatus: 200, - ResponseBody: `{"id":"58f86fab-85c5-4f7c-9b68-9c323248afc4:0"}`, - SendPrep: setSendURL, + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "whatsapp:14133881111", + ExpectedStatus: "W", + ExpectedExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", + ExpectedRequestPath: "/v1/SID/messages", + ExpectedHeaders: map[string]string{"Content-type": "application/x-www-form-urlencoded"}, + ExpectedRequestBody: "api-key=123456&body=Simple+Message&callback_url=https%3A%2F%2Flocalhost%2Fc%2Fkwa%2F8eb23e93-5ecb-45ba-b726-3b064e0c568c%2Fstatus&channel=WhatsApp&from=250788383383&to=14133881111&type=text", + MockResponseStatus: 200, + MockResponseBody: `{"id":"58f86fab-85c5-4f7c-9b68-9c323248afc4:0"}`, + SendPrep: setSendURL, }, { - Label: "Unicode Send", - Text: "☺", - URN: "whatsapp:14133881111", - Status: "W", - ExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", - Path: "/v1/SID/messages", - Headers: map[string]string{"Content-type": "application/x-www-form-urlencoded"}, - RequestBody: "api-key=123456&body=%E2%98%BA&callback_url=https%3A%2F%2Flocalhost%2Fc%2Fkwa%2F8eb23e93-5ecb-45ba-b726-3b064e0c568c%2Fstatus&channel=WhatsApp&from=250788383383&to=14133881111&type=text", - ResponseStatus: 200, - ResponseBody: `{"id":"58f86fab-85c5-4f7c-9b68-9c323248afc4:0"}`, - SendPrep: setSendURL, + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "whatsapp:14133881111", + ExpectedStatus: "W", + ExpectedExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", + ExpectedRequestPath: "/v1/SID/messages", + ExpectedHeaders: map[string]string{"Content-type": "application/x-www-form-urlencoded"}, + ExpectedRequestBody: "api-key=123456&body=%E2%98%BA&callback_url=https%3A%2F%2Flocalhost%2Fc%2Fkwa%2F8eb23e93-5ecb-45ba-b726-3b064e0c568c%2Fstatus&channel=WhatsApp&from=250788383383&to=14133881111&type=text", + MockResponseStatus: 200, + MockResponseBody: `{"id":"58f86fab-85c5-4f7c-9b68-9c323248afc4:0"}`, + SendPrep: setSendURL, }, { - Label: "URL Send", - Text: "foo https://foo.bar bar", - URN: "whatsapp:14133881111", - Status: "W", - ExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", - Path: "/v1/SID/messages", - Headers: map[string]string{"Content-type": "application/x-www-form-urlencoded"}, - RequestBody: "api-key=123456&body=foo+https%3A%2F%2Ffoo.bar+bar&callback_url=https%3A%2F%2Flocalhost%2Fc%2Fkwa%2F8eb23e93-5ecb-45ba-b726-3b064e0c568c%2Fstatus&channel=WhatsApp&from=250788383383&preview_url=true&to=14133881111&type=text", - ResponseStatus: 200, - ResponseBody: `{"id":"58f86fab-85c5-4f7c-9b68-9c323248afc4:0"}`, - SendPrep: setSendURL, + Label: "URL Send", + MsgText: "foo https://foo.bar bar", + MsgURN: "whatsapp:14133881111", + ExpectedStatus: "W", + ExpectedExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", + ExpectedRequestPath: "/v1/SID/messages", + ExpectedHeaders: map[string]string{"Content-type": "application/x-www-form-urlencoded"}, + ExpectedRequestBody: "api-key=123456&body=foo+https%3A%2F%2Ffoo.bar+bar&callback_url=https%3A%2F%2Flocalhost%2Fc%2Fkwa%2F8eb23e93-5ecb-45ba-b726-3b064e0c568c%2Fstatus&channel=WhatsApp&from=250788383383&preview_url=true&to=14133881111&type=text", + MockResponseStatus: 200, + MockResponseBody: `{"id":"58f86fab-85c5-4f7c-9b68-9c323248afc4:0"}`, + SendPrep: setSendURL, }, { - Label: "Plain Send Error", - Text: "Error", - URN: "whatsapp:14133881112", - Status: "F", - Path: "/v1/SID/messages", - Headers: map[string]string{"Content-type": "application/x-www-form-urlencoded"}, - RequestBody: "api-key=123456&body=Error&callback_url=https%3A%2F%2Flocalhost%2Fc%2Fkwa%2F8eb23e93-5ecb-45ba-b726-3b064e0c568c%2Fstatus&channel=WhatsApp&from=250788383383&to=14133881112&type=text", - ResponseStatus: 400, - ResponseBody: `{"error":{"to":"invalid number"}}`, - SendPrep: setSendURL, + Label: "Plain Send Error", + MsgText: "Error", + MsgURN: "whatsapp:14133881112", + ExpectedStatus: "F", + ExpectedRequestPath: "/v1/SID/messages", + ExpectedHeaders: map[string]string{"Content-type": "application/x-www-form-urlencoded"}, + ExpectedRequestBody: "api-key=123456&body=Error&callback_url=https%3A%2F%2Flocalhost%2Fc%2Fkwa%2F8eb23e93-5ecb-45ba-b726-3b064e0c568c%2Fstatus&channel=WhatsApp&from=250788383383&to=14133881112&type=text", + MockResponseStatus: 400, + MockResponseBody: `{"error":{"to":"invalid number"}}`, + SendPrep: setSendURL, }, { - Label: "Medias Send", - Text: "Medias", - Attachments: []string{"image/jpg:https://foo.bar/image.jpg", "image/png:https://foo.bar/video.mp4"}, - URN: "whatsapp:14133881111", - Status: "W", - ExternalID: "f75fbe1e-a0c0-4923-96e8-5043aa617b2b:0", - Responses: map[MockedRequest]MockedResponse{ + Label: "Medias Send", + MsgText: "Medias", + MsgAttachments: []string{"image/jpg:https://foo.bar/image.jpg", "image/png:https://foo.bar/video.mp4"}, + MsgURN: "whatsapp:14133881111", + ExpectedStatus: "W", + ExpectedExternalID: "f75fbe1e-a0c0-4923-96e8-5043aa617b2b:0", + MockResponses: map[MockedRequest]MockedResponse{ MockedRequest{ Method: "POST", Path: "/v1/SID/messages", @@ -195,12 +195,12 @@ var sendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL, }, { - Label: "Media Send Error", - Text: "Medias", - Attachments: []string{"image/jpg:https://foo.bar/image.jpg", "image/png:https://foo.bar/video.wmv"}, - URN: "whatsapp:14133881111", - Status: "F", - Responses: map[MockedRequest]MockedResponse{ + Label: "Media Send Error", + MsgText: "Medias", + MsgAttachments: []string{"image/jpg:https://foo.bar/image.jpg", "image/png:https://foo.bar/video.wmv"}, + MsgURN: "whatsapp:14133881111", + ExpectedStatus: "F", + MockResponses: map[MockedRequest]MockedResponse{ MockedRequest{ Method: "POST", Path: "/v1/SID/messages", @@ -228,8 +228,8 @@ func mockAttachmentURLs(mediaServer *httptest.Server, testCases []ChannelSendTes for i, testCase := range testCases { mockedCase := testCase - for j, attachment := range testCase.Attachments { - mockedCase.Attachments[j] = strings.Replace(attachment, "https://foo.bar", mediaServer.URL, 1) + for j, attachment := range testCase.MsgAttachments { + mockedCase.MsgAttachments[j] = strings.Replace(attachment, "https://foo.bar", mediaServer.URL, 1) } casesWithMockedUrls[i] = mockedCase } diff --git a/handlers/kannel/kannel_test.go b/handlers/kannel/kannel_test.go index 765c5940b..74b357672 100644 --- a/handlers/kannel/kannel_test.go +++ b/handlers/kannel/kannel_test.go @@ -73,57 +73,57 @@ func setSendURLWithQuery(s *httptest.Server, h courier.ChannelHandler, c courier var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", HighPriority: false, - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - URLParams: map[string]string{"text": "Simple Message", "to": "+250788383383", "coding": "", "priority": "", + MsgText: "Simple Message", MsgURN: "tel:+250788383383", MsgHighPriority: false, + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "Simple Message", "to": "+250788383383", "coding": "", "priority": "", "dlr-url": "https://localhost/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%d"}, SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "tel:+250788383383", HighPriority: false, - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - URLParams: map[string]string{"text": "☺", "to": "+250788383383", "coding": "2", "charset": "utf8", "priority": ""}, - SendPrep: setSendURL}, + MsgText: "☺", MsgURN: "tel:+250788383383", MsgHighPriority: false, + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "☺", "to": "+250788383383", "coding": "2", "charset": "utf8", "priority": ""}, + SendPrep: setSendURL}, {Label: "Smart Encoding", - Text: "Fancy “Smart” Quotes", URN: "tel:+250788383383", HighPriority: false, - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - URLParams: map[string]string{"text": `Fancy "Smart" Quotes`, "to": "+250788383383", "coding": "", "priority": ""}, - SendPrep: setSendURL}, + MsgText: "Fancy “Smart” Quotes", MsgURN: "tel:+250788383383", MsgHighPriority: false, + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": `Fancy "Smart" Quotes`, "to": "+250788383383", "coding": "", "priority": ""}, + SendPrep: setSendURL}, {Label: "Not Routable", - Text: "Not Routable", URN: "tel:+250788383383", HighPriority: false, - Status: "F", - ResponseBody: "Not routable. Do not try again.", ResponseStatus: 403, - URLParams: map[string]string{"text": `Not Routable`, "to": "+250788383383", "coding": "", "priority": ""}, - SendPrep: setSendURL}, + MsgText: "Not Routable", MsgURN: "tel:+250788383383", MsgHighPriority: false, + ExpectedStatus: "F", + MockResponseBody: "Not routable. Do not try again.", MockResponseStatus: 403, + ExpectedURLParams: map[string]string{"text": `Not Routable`, "to": "+250788383383", "coding": "", "priority": ""}, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", HighPriority: false, - Status: "E", - ResponseBody: "1: Unknown channel", ResponseStatus: 401, - URLParams: map[string]string{"text": `Error Message`, "to": "+250788383383", "coding": "", "priority": ""}, - SendPrep: setSendURL}, + MsgText: "Error Message", MsgURN: "tel:+250788383383", MsgHighPriority: false, + ExpectedStatus: "E", + MockResponseBody: "1: Unknown channel", MockResponseStatus: 401, + ExpectedURLParams: map[string]string{"text": `Error Message`, "to": "+250788383383", "coding": "", "priority": ""}, + SendPrep: setSendURL}, {Label: "Custom Params", - Text: "Custom Params", URN: "tel:+250788383383", HighPriority: true, - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 201, - URLParams: map[string]string{"text": `Custom Params`, "to": "+250788383383", "coding": "", "priority": "1", "auth": "foo"}, - SendPrep: setSendURLWithQuery}, + MsgText: "Custom Params", MsgURN: "tel:+250788383383", MsgHighPriority: true, + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 201, + ExpectedURLParams: map[string]string{"text": `Custom Params`, "to": "+250788383383", "coding": "", "priority": "1", "auth": "foo"}, + SendPrep: setSendURLWithQuery}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", HighPriority: true, Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `0: Accepted for delivery`, ResponseStatus: 200, - URLParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "+250788383383", "from": "2020", "dlr-mask": "27"}, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgHighPriority: true, MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: `0: Accepted for delivery`, MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "+250788383383", "from": "2020", "dlr-mask": "27"}, + SendPrep: setSendURL}, } var nationalSendTestCases = []ChannelSendTestCase{ {Label: "National Send", - Text: "success", URN: "tel:+250788383383", HighPriority: true, - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - URLParams: map[string]string{"text": "success", "to": "788383383", "coding": "", "priority": "1", "dlr-mask": "3"}, - SendPrep: setSendURL}, + MsgText: "success", MsgURN: "tel:+250788383383", MsgHighPriority: true, + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "success", "to": "788383383", "coding": "", "priority": "1", "dlr-mask": "3"}, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index f9c814edf..46bb77f6a 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -326,100 +326,100 @@ Proin vulputate id justo non aliquet.` var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "line:uabcdefghij", - Status: "W", - ResponseBody: `{}`, ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message", MsgURN: "line:uabcdefghij", + ExpectedStatus: "W", + MockResponseBody: `{}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken", }, - RequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Simple Message"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Simple Message"}]}`, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "Simple Message ☺", URN: "line:uabcdefghij", - Status: "W", - ResponseBody: `{}`, ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message ☺", MsgURN: "line:uabcdefghij", + ExpectedStatus: "W", + MockResponseBody: `{}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken", }, - RequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Simple Message ☺"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Simple Message ☺"}]}`, + SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "line:uabcdefghij", - Status: "W", - ResponseBody: `{}`, ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "line:uabcdefghij", + ExpectedStatus: "W", + MockResponseBody: `{}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken", }, - RequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say,"},{"type":"text","text":"I need to keep adding more things to make it work"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say,"},{"type":"text","text":"I need to keep adding more things to make it work"}]}`, + SendPrep: setSendURL}, {Label: "Send Image Attachment", - Text: "My pic!", URN: "line:uabcdefghij", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `{}`, ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "My pic!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: `{}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken", }, - RequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My pic!"},{"type":"image","originalContentUrl":"https://foo.bar/image.jpg","previewImageUrl":"https://foo.bar/image.jpg"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My pic!"},{"type":"image","originalContentUrl":"https://foo.bar/image.jpg","previewImageUrl":"https://foo.bar/image.jpg"}]}`, + SendPrep: setSendURL}, {Label: "Send Other Attachment", - Text: "My video!", URN: "line:uabcdefghij", Attachments: []string{"video/mp4:https://foo.bar/video.mp4"}, - Status: "W", - ResponseBody: `{}`, ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "My video!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, + ExpectedStatus: "W", + MockResponseBody: `{}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken", }, - RequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My video!"},{"type":"text","text":"https://foo.bar/video.mp4"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My video!"},{"type":"text","text":"https://foo.bar/video.mp4"}]}`, + SendPrep: setSendURL}, {Label: "Send Message Batches", - Text: tooLongMsg, - URN: "line:uabcdefghij", - Status: "W", - ResponseBody: `{}`, ResponseStatus: 200, - Headers: map[string]string{ + MsgText: tooLongMsg, + MsgURN: "line:uabcdefghij", + ExpectedStatus: "W", + MockResponseBody: `{}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken", }, - RequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Sed hendrerit nisi vitae nisl ornare tristique.\nProin vulputate id justo non aliquet."}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Sed hendrerit nisi vitae nisl ornare tristique.\nProin vulputate id justo non aliquet."}]}`, + SendPrep: setSendURL}, {Label: "Send Reply Message", - Text: "Simple Message", URN: "line:uabcdefghij", ResponseToExternalID: "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA", - Status: "W", - ResponseBody: `{}`, ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message", MsgURN: "line:uabcdefghij", MsgResponseToExternalID: "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA", + ExpectedStatus: "W", + MockResponseBody: `{}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken", }, - RequestBody: `{"replyToken":"nHuyWiB7yP5Zw52FIkcQobQuGDXCTA","messages":[{"type":"text","text":"Simple Message"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"replyToken":"nHuyWiB7yP5Zw52FIkcQobQuGDXCTA","messages":[{"type":"text","text":"Simple Message"}]}`, + SendPrep: setSendURL}, {Label: "Quick Reply", - Text: "Are you happy?", URN: "line:uabcdefghij", - QuickReplies: []string{"Yes", "No"}, - Status: "W", - ResponseBody: `{}`, ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Are you happy?", MsgURN: "line:uabcdefghij", + MsgQuickReplies: []string{"Yes", "No"}, + ExpectedStatus: "W", + MockResponseBody: `{}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken", }, - RequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Are you happy?","quickReply":{"items":[{"type":"action","action":{"type":"message","label":"Yes","text":"Yes"}},{"type":"action","action":{"type":"message","label":"No","text":"No"}}]}}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Are you happy?","quickReply":{"items":[{"type":"action","action":{"type":"message","label":"Yes","text":"Yes"}},{"type":"action","action":{"type":"message","label":"No","text":"No"}}]}}]}`, + SendPrep: setSendURL}, {Label: "Send Push Message If Invalid Reply", - Text: "Simple Message", URN: "line:uabcdefghij", ResponseToExternalID: "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA", - Status: "W", - Responses: map[MockedRequest]MockedResponse{ + MsgText: "Simple Message", MsgURN: "line:uabcdefghij", MsgResponseToExternalID: "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA", + ExpectedStatus: "W", + MockResponses: map[MockedRequest]MockedResponse{ MockedRequest{ Method: "POST", Path: "/v2/bot/message/reply", @@ -439,11 +439,11 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Sending", URN: "line:uabcdefghij", - Status: "E", - ResponseBody: `{"message": "Error"}`, ResponseStatus: 403, - RequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Error Sending"}]}`, - SendPrep: setSendURL}, + MsgText: "Error Sending", MsgURN: "line:uabcdefghij", + ExpectedStatus: "E", + MockResponseBody: `{"message": "Error"}`, MockResponseStatus: 403, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Error Sending"}]}`, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/m3tech/m3tech_test.go b/handlers/m3tech/m3tech_test.go index 6130c718c..aecd13dce 100644 --- a/handlers/m3tech/m3tech_test.go +++ b/handlers/m3tech/m3tech_test.go @@ -40,10 +40,10 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - ResponseBody: `[{"Response": "0"}]`, ResponseStatus: 200, - URLParams: map[string]string{ + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, + ExpectedURLParams: map[string]string{ "MobileNo": "250788383383", "SMS": "Simple Message", "SMSChannel": "0", @@ -57,27 +57,27 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "tel:+250788383383", - Status: "W", - ResponseBody: `[{"Response": "0"}]`, ResponseStatus: 200, - URLParams: map[string]string{"SMS": "☺", "SMSType": "7"}, - SendPrep: setSendURL}, + MsgText: "☺", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"SMS": "☺", "SMSType": "7"}, + SendPrep: setSendURL}, {Label: "Smart Encoding", - Text: "Fancy “Smart” Quotes", URN: "tel:+250788383383", - Status: "W", - ResponseBody: `[{"Response": "0"}]`, ResponseStatus: 200, - URLParams: map[string]string{"SMS": `Fancy "Smart" Quotes`, "SMSType": "0"}, - SendPrep: setSendURL}, + MsgText: "Fancy “Smart” Quotes", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"SMS": `Fancy "Smart" Quotes`, "SMSType": "0"}, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `[{"Response": "0"}]`, ResponseStatus: 200, - URLParams: map[string]string{"SMS": "My pic!\nhttps://foo.bar/image.jpg", "SMSType": "0"}, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"SMS": "My pic!\nhttps://foo.bar/image.jpg", "SMSType": "0"}, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Sending", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `[{"Response": "101"}]`, ResponseStatus: 403, + MsgText: "Error Sending", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `[{"Response": "101"}]`, MockResponseStatus: 403, SendPrep: setSendURL}, } diff --git a/handlers/macrokiosk/macrokiosk_test.go b/handlers/macrokiosk/macrokiosk_test.go index 1a47f83ec..0190fc1e4 100644 --- a/handlers/macrokiosk/macrokiosk_test.go +++ b/handlers/macrokiosk/macrokiosk_test.go @@ -64,66 +64,66 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", - URN: "tel:+250788383383", - Status: "W", - ExternalID: "abc123", - ResponseBody: `{ "MsgID":"abc123" }`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "abc123", + MockResponseBody: `{ "MsgID":"abc123" }`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"user":"Username","pass":"Password","to":"250788383383","text":"Simple Message ☺","from":"macro","servid":"service-id","type":"5"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"user":"Username","pass":"Password","to":"250788383383","text":"Simple Message ☺","from":"macro","servid":"service-id","type":"5"}`, + SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+250788383383", - Status: "W", - ExternalID: "abc123", - ResponseBody: `{ "MsgID":"abc123" }`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "abc123", + MockResponseBody: `{ "MsgID":"abc123" }`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"user":"Username","pass":"Password","to":"250788383383","text":"I need to keep adding more things to make it work","from":"macro","servid":"service-id","type":"0"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"user":"Username","pass":"Password","to":"250788383383","text":"I need to keep adding more things to make it work","from":"macro","servid":"service-id","type":"0"}`, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", - URN: "tel:+250788383383", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ExternalID: "abc123", - ResponseBody: `{ "MsgID":"abc123" }`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + ExpectedExternalID: "abc123", + MockResponseBody: `{ "MsgID":"abc123" }`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"user":"Username","pass":"Password","to":"250788383383","text":"My pic!\nhttps://foo.bar/image.jpg","from":"macro","servid":"service-id","type":"0"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"user":"Username","pass":"Password","to":"250788383383","text":"My pic!\nhttps://foo.bar/image.jpg","from":"macro","servid":"service-id","type":"0"}`, + SendPrep: setSendURL}, {Label: "No External Id", - Text: "No External ID", - URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, - ResponseStatus: 200, - Error: "unable to parse response body from Macrokiosk", - Headers: map[string]string{ + MsgText: "No External ID", + MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, + MockResponseStatus: 200, + ExpectedError: "unable to parse response body from Macrokiosk", + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"user":"Username","pass":"Password","to":"250788383383","text":"No External ID","from":"macro","servid":"service-id","type":"0"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"user":"Username","pass":"Password","to":"250788383383","text":"No External ID","from":"macro","servid":"service-id","type":"0"}`, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", - URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "failed" }`, - ResponseStatus: 401, - RequestBody: `{"user":"Username","pass":"Password","to":"250788383383","text":"Error Message","from":"macro","servid":"service-id","type":"0"}`, - SendPrep: setSendURL}, + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{ "error": "failed" }`, + MockResponseStatus: 401, + ExpectedRequestBody: `{"user":"Username","pass":"Password","to":"250788383383","text":"Error Message","from":"macro","servid":"service-id","type":"0"}`, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/mblox/mblox_test.go b/handlers/mblox/mblox_test.go index 96972c161..8bdf97611 100644 --- a/handlers/mblox/mblox_test.go +++ b/handlers/mblox/mblox_test.go @@ -88,70 +88,70 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", - URN: "tel:+250788383383", - Status: "W", - ExternalID: "", - ResponseBody: `{ "id":"OzYDlvf3SQVc" }`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseBody: `{ "id":"OzYDlvf3SQVc" }`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer Password", }, - RequestBody: `{"from":"2020","to":["250788383383"],"body":"Simple Message ☺","delivery_report":"per_recipient"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"from":"2020","to":["250788383383"],"body":"Simple Message ☺","delivery_report":"per_recipient"}`, + SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+250788383383", - Status: "W", - ExternalID: "", - ResponseBody: `{ "id":"OzYDlvf3SQVc" }`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseBody: `{ "id":"OzYDlvf3SQVc" }`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer Password", }, - RequestBody: `{"from":"2020","to":["250788383383"],"body":"I need to keep adding more things to make it work","delivery_report":"per_recipient"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"from":"2020","to":["250788383383"],"body":"I need to keep adding more things to make it work","delivery_report":"per_recipient"}`, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", - URN: "tel:+250788383383", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ExternalID: "", - ResponseBody: `{ "id":"OzYDlvf3SQVc" }`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseBody: `{ "id":"OzYDlvf3SQVc" }`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer Password", }, - RequestBody: `{"from":"2020","to":["250788383383"],"body":"My pic!\nhttps://foo.bar/image.jpg","delivery_report":"per_recipient"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"from":"2020","to":["250788383383"],"body":"My pic!\nhttps://foo.bar/image.jpg","delivery_report":"per_recipient"}`, + SendPrep: setSendURL}, {Label: "No External Id", - Text: "No External ID", - URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, - ResponseStatus: 200, - Error: "unable to parse response body from MBlox", - Headers: map[string]string{ + MsgText: "No External ID", + MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, + MockResponseStatus: 200, + ExpectedError: "unable to parse response body from MBlox", + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer Password", }, - RequestBody: `{"from":"2020","to":["250788383383"],"body":"No External ID","delivery_report":"per_recipient"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"from":"2020","to":["250788383383"],"body":"No External ID","delivery_report":"per_recipient"}`, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", - URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "failed" }`, - ResponseStatus: 401, - RequestBody: `{"from":"2020","to":["250788383383"],"body":"Error Message","delivery_report":"per_recipient"}`, - SendPrep: setSendURL}, + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{ "error": "failed" }`, + MockResponseStatus: 401, + ExpectedRequestBody: `{"from":"2020","to":["250788383383"],"body":"Error Message","delivery_report":"per_recipient"}`, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/messangi/messangi_test.go b/handlers/messangi/messangi_test.go index 81d817030..bde778662 100644 --- a/handlers/messangi/messangi_test.go +++ b/handlers/messangi/messangi_test.go @@ -8,7 +8,6 @@ import ( . "github.com/nyaruka/courier/handlers" ) - var testChannels = []courier.Channel{ courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MG", "2020", "JM", nil), } @@ -38,48 +37,48 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, sendURL = s.URL } -var defaultSendTestCases = []ChannelSendTestCase { +var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", URN: "tel:+18765422035", - Status: "W", ExternalID: "", - ResponseBody: `sendMTOKCompleted`, - ResponseStatus: 200, - SendPrep: setSendURL}, + MsgText: "Simple Message ☺", MsgURN: "tel:+18765422035", + ExpectedStatus: "W", ExpectedExternalID: "", + MockResponseBody: `sendMTOKCompleted`, + MockResponseStatus: 200, + SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+18765422035", - Status: "W", - ExternalID: "", - ResponseBody: `sendMTOKCompleted`, - ResponseStatus: 200, - SendPrep: setSendURL}, + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+18765422035", + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseBody: `sendMTOKCompleted`, + MockResponseStatus: 200, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+18765422035", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", ExternalID: "", - ResponseBody: `sendMTOKCompleted`, - ResponseStatus: 200, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+18765422035", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", ExpectedExternalID: "", + MockResponseBody: `sendMTOKCompleted`, + MockResponseStatus: 200, + SendPrep: setSendURL}, {Label: "Invalid Parameters", - Text: "Invalid Parameters", URN: "tel:+18765422035", - Status: "E", - ResponseBody: "", ResponseStatus: 404, + MsgText: "Invalid Parameters", MsgURN: "tel:+18765422035", + ExpectedStatus: "E", + MockResponseBody: "", MockResponseStatus: 404, SendPrep: setSendURL}, {Label: "Error Response", - Text: "Error Response", URN: "tel:+18765422035", - Status: "F", - ResponseBody: `sendMTERRORCompleted`, - ResponseStatus: 200, - SendPrep: setSendURL}, + MsgText: "Error Response", MsgURN: "tel:+18765422035", + ExpectedStatus: "F", + MockResponseBody: `sendMTERRORCompleted`, + MockResponseStatus: 200, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { maxMsgLength = 160 var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MG", "2020", "JM", map[string]interface{}{ - "public_key": "my-public-key", + "public_key": "my-public-key", "private_key": "my-private-key", "instance_id": 7, - "carrier_id": 2, + "carrier_id": 2, }) RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) } diff --git a/handlers/mtarget/mtarget_test.go b/handlers/mtarget/mtarget_test.go index ac1e4ee8d..7453c887e 100644 --- a/handlers/mtarget/mtarget_test.go +++ b/handlers/mtarget/mtarget_test.go @@ -64,10 +64,10 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - ResponseBody: `{"results":[{"code": "0", "ticket": "externalID"}]}`, ResponseStatus: 200, - URLParams: map[string]string{ + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: `{"results":[{"code": "0", "ticket": "externalID"}]}`, MockResponseStatus: 200, + ExpectedURLParams: map[string]string{ "msisdn": "+250788383383", "msg": "Simple Message", "username": "Username", @@ -77,26 +77,26 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "tel:+250788383383", - Status: "W", - ResponseBody: `{"results":[{"code": "0", "ticket": "externalID"}]}`, ResponseStatus: 200, - URLParams: map[string]string{"msg": "☺"}, - SendPrep: setSendURL}, + MsgText: "☺", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: `{"results":[{"code": "0", "ticket": "externalID"}]}`, MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"msg": "☺"}, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `{"results":[{"code": "0", "ticket": "externalID"}]}`, ResponseStatus: 200, - URLParams: map[string]string{"msg": "My pic!\nhttps://foo.bar/image.jpg"}, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: `{"results":[{"code": "0", "ticket": "externalID"}]}`, MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"msg": "My pic!\nhttps://foo.bar/image.jpg"}, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Sending", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{"results":[{"code": "3", "ticket": "null"}]}`, ResponseStatus: 403, + MsgText: "Error Sending", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{"results":[{"code": "3", "ticket": "null"}]}`, MockResponseStatus: 403, SendPrep: setSendURL}, {Label: "Error Response", - Text: "Error Sending", URN: "tel:+250788383383", - Status: "F", - ResponseBody: `{"results":[{"code": "3", "ticket": "null"}]}`, ResponseStatus: 200, + MsgText: "Error Sending", MsgURN: "tel:+250788383383", + ExpectedStatus: "F", + MockResponseBody: `{"results":[{"code": "3", "ticket": "null"}]}`, MockResponseStatus: 200, SendPrep: setSendURL}, } diff --git a/handlers/nexmo/nexmo_test.go b/handlers/nexmo/nexmo_test.go index 0ab09b63f..5a434e0ad 100644 --- a/handlers/nexmo/nexmo_test.go +++ b/handlers/nexmo/nexmo_test.go @@ -60,53 +60,53 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", ExternalID: "1002", - PostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - ResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, ResponseStatus: 200, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", ExpectedExternalID: "1002", + ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, + MockResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "Unicode ☺", URN: "tel:+250788383383", - Status: "W", ExternalID: "1002", - PostParams: map[string]string{"text": "Unicode ☺", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "unicode"}, - ResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, ResponseStatus: 200, + MsgText: "Unicode ☺", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", ExpectedExternalID: "1002", + ExpectedPostParams: map[string]string{"text": "Unicode ☺", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "unicode"}, + MockResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+250788383383", - Status: "W", ExternalID: "1002", - PostParams: map[string]string{"text": "I need to keep adding more things to make it work", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - ResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, ResponseStatus: 200, + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", ExpectedExternalID: "1002", + ExpectedPostParams: map[string]string{"text": "I need to keep adding more things to make it work", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, + MockResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", ExternalID: "1002", - PostParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - ResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, ResponseStatus: 200, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", ExpectedExternalID: "1002", + ExpectedPostParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, + MockResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Error Status", - Text: "Error status", URN: "tel:+250788383383", - Status: "E", - PostParams: map[string]string{"text": "Error status", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - ResponseBody: `{"messages":[{"status":"10"}]}`, ResponseStatus: 200, + MsgText: "Error status", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + ExpectedPostParams: map[string]string{"text": "Error status", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, + MockResponseBody: `{"messages":[{"status":"10"}]}`, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - PostParams: map[string]string{"text": "Error Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - ResponseBody: `Error`, ResponseStatus: 400, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + ExpectedPostParams: map[string]string{"text": "Error Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, + MockResponseBody: `Error`, MockResponseStatus: 400, SendPrep: setSendURL}, {Label: "Invalid Token", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "E", - PostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - ResponseBody: "Invalid API token", ResponseStatus: 401, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, + MockResponseBody: "Invalid API token", MockResponseStatus: 401, SendPrep: setSendURL}, {Label: "Throttled by Nexmo", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "E", - PostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - ResponseBody: `{"messages":[{"status":"1","error-text":"Throughput Rate Exceeded - please wait [ 250 ] and retry"}]}`, ResponseStatus: 200, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, + MockResponseBody: `{"messages":[{"status":"1","error-text":"Throughput Rate Exceeded - please wait [ 250 ] and retry"}]}`, MockResponseStatus: 200, SendPrep: setSendURL}, } diff --git a/handlers/novo/novo_test.go b/handlers/novo/novo_test.go index 1f6d0d0c7..c49d77283 100644 --- a/handlers/novo/novo_test.go +++ b/handlers/novo/novo_test.go @@ -8,12 +8,11 @@ import ( . "github.com/nyaruka/courier/handlers" ) - var testChannels = []courier.Channel{ courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "NV", "2020", "TT", map[string]interface{}{ - "merchant_id": "my-merchant-id", + "merchant_id": "my-merchant-id", "merchant_secret": "my-merchant-secret", - "secret": "sesame", + "secret": "sesame", }), } @@ -45,48 +44,48 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, sendURL = s.URL + "?%s" } -var defaultSendTestCases = []ChannelSendTestCase { +var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", URN: "tel:+18686846481", - Status: "W", ExternalID: "", - ResponseBody: `{"blastId": "-437733473338","status": "FINISHED","type": "SMS","statusDescription": "Finished"}`, - ResponseStatus: 200, - SendPrep: setSendURL}, + MsgText: "Simple Message ☺", MsgURN: "tel:+18686846481", + ExpectedStatus: "W", ExpectedExternalID: "", + MockResponseBody: `{"blastId": "-437733473338","status": "FINISHED","type": "SMS","statusDescription": "Finished"}`, + MockResponseStatus: 200, + SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+18686846481", - Status: "W", - ExternalID: "", - ResponseBody: `{"blastId": "-437733473338","status": "FINISHED","type": "SMS","statusDescription": "Finished"}`, - ResponseStatus: 200, - SendPrep: setSendURL}, + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+18686846481", + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseBody: `{"blastId": "-437733473338","status": "FINISHED","type": "SMS","statusDescription": "Finished"}`, + MockResponseStatus: 200, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+18686846481", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", ExternalID: "", - ResponseBody: `{"blastId": "-437733473338","status": "FINISHED","type": "SMS","statusDescription": "Finished"}`, - ResponseStatus: 200, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+18686846481", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", ExpectedExternalID: "", + MockResponseBody: `{"blastId": "-437733473338","status": "FINISHED","type": "SMS","statusDescription": "Finished"}`, + MockResponseStatus: 200, + SendPrep: setSendURL}, {Label: "Invalid Parameters", - Text: "Invalid Parameters", URN: "tel:+18686846481", - Status: "F", - ResponseBody: `{"error": "Incorrect Query String Authentication ","expectedQueryString": "8868;18686846480;test;"}`, - ResponseStatus: 200, - SendPrep: setSendURL}, + MsgText: "Invalid Parameters", MsgURN: "tel:+18686846481", + ExpectedStatus: "F", + MockResponseBody: `{"error": "Incorrect Query String Authentication ","expectedQueryString": "8868;18686846480;test;"}`, + MockResponseStatus: 200, + SendPrep: setSendURL}, {Label: "Error Response", - Text: "Error Response", URN: "tel:+18686846481", - Status: "F", - ResponseBody: `{"error": "Incorrect Query String Authentication ","expectedQueryString": "8868;18686846480;test;"}`, - ResponseStatus: 200, - SendPrep: setSendURL}, + MsgText: "Error Response", MsgURN: "tel:+18686846481", + ExpectedStatus: "F", + MockResponseBody: `{"error": "Incorrect Query String Authentication ","expectedQueryString": "8868;18686846480;test;"}`, + MockResponseStatus: 200, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { maxMsgLength = 160 var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "NV", "2020", "TT", map[string]interface{}{ - "merchant_id": "my-merchant-id", + "merchant_id": "my-merchant-id", "merchant_secret": "my-merchant-secret", - "secret": "sesame", + "secret": "sesame", }) RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) } diff --git a/handlers/playmobile/playmobile_test.go b/handlers/playmobile/playmobile_test.go index a910c5145..03ee4180e 100644 --- a/handlers/playmobile/playmobile_test.go +++ b/handlers/playmobile/playmobile_test.go @@ -87,34 +87,34 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid", - URL: receiveURL, - Data: validReceive, + URL: receiveURL, + Data: validReceive, Response: "Accepted", - Status: 200, - Text: Sp("SMS Response Accepted"), - URN: Sp("tel:+998999999999")}, + Status: 200, + Text: Sp("SMS Response Accepted"), + URN: Sp("tel:+998999999999")}, {Label: "Receive Missing MSISDN", - URL: receiveURL, - Data: invalidReceive, + URL: receiveURL, + Data: invalidReceive, Response: "missing required fields msidsn or id", - Status: 400}, + Status: 400}, {Label: "No Messages", - URL: receiveURL, - Data: noMessages, + URL: receiveURL, + Data: noMessages, Response: "no messages, ignored", - Status: 200}, + Status: 200}, {Label: "Invalid XML", - URL: receiveURL, - Data: invalidXML, + URL: receiveURL, + Data: invalidXML, Response: "", - Status: 405}, + Status: 405}, {Label: "Receive With Prefix", - URL: receiveURL, - Data: receiveWithPrefix, + URL: receiveURL, + Data: receiveWithPrefix, Response: "Accepted", - Status: 200, - Text: Sp("SMS Response Accepted"), - URN: Sp("tel:+998999999999")}, + Status: 200, + Text: Sp("SMS Response Accepted"), + URN: Sp("tel:+998999999999")}, {Label: "Receive With Prefix Only", URL: receiveURL, Data: receiveWithPrefixOnly, @@ -136,55 +136,55 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", - URN: "tel:99999999999", - Status: "W", - ExternalID: "", - ResponseBody: "Request is received", - ResponseStatus: 200, - RequestBody: `{"messages":[{"recipient":"99999999999","message-id":"10","sms":{"originator":"1122","content":{"text":"Simple Message"}}}]}`, - SendPrep: setSendURL}, + MsgText: "Simple Message", + MsgURN: "tel:99999999999", + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseBody: "Request is received", + MockResponseStatus: 200, + ExpectedRequestBody: `{"messages":[{"recipient":"99999999999","message-id":"10","sms":{"originator":"1122","content":{"text":"Simple Message"}}}]}`, + SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 640 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, This is a longer message than 640 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, This is a longer message than 640 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, This is a longer message than 640 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, now, I need to keep adding more things to make it work", - URN: "tel:99999999999", - Status: "W", - ExternalID: "", - ResponseBody: "Request is received", - ResponseStatus: 200, - RequestBody: `{"messages":[{"recipient":"99999999999","message-id":"10.2","sms":{"originator":"1122","content":{"text":"I need to keep adding more things to make it work"}}}]}`, - SendPrep: setSendURL}, + MsgText: "This is a longer message than 640 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, This is a longer message than 640 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, This is a longer message than 640 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, This is a longer message than 640 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, now, I need to keep adding more things to make it work", + MsgURN: "tel:99999999999", + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseBody: "Request is received", + MockResponseStatus: 200, + ExpectedRequestBody: `{"messages":[{"recipient":"99999999999","message-id":"10.2","sms":{"originator":"1122","content":{"text":"I need to keep adding more things to make it work"}}}]}`, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", - URN: "tel:+18686846481", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ExternalID: "", - ResponseBody: validMessage, - ResponseStatus: 200, - SendPrep: setSendURL}, + MsgText: "My pic!", + MsgURN: "tel:+18686846481", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseBody: validMessage, + MockResponseStatus: 200, + SendPrep: setSendURL}, {Label: "Invalid JSON Response", - Text: "Error Sending", - URN: "tel:+250788383383", - Status: "E", - ResponseStatus: 400, - ResponseBody: "not json", - SendPrep: setSendURL}, + MsgText: "Error Sending", + MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseStatus: 400, + MockResponseBody: "not json", + SendPrep: setSendURL}, {Label: "Missing Message ID", - Text: missingMessageID, - URN: "tel:+250788383383", - Status: "E", - ResponseStatus: 400, - ResponseBody: "{}", - SendPrep: setSendURL}, + MsgText: missingMessageID, + MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseStatus: 400, + MockResponseBody: "{}", + SendPrep: setSendURL}, } func TestSending(t *testing.T) { var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "PM", "1122", "UZ", map[string]interface{}{ - "password": "Password", - "username": "Username", + "password": "Password", + "username": "Username", "shortcode": "1122", - "base_url": "http://91.204.239.42", + "base_url": "http://91.204.239.42", }) RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) diff --git a/handlers/plivo/plivo_test.go b/handlers/plivo/plivo_test.go index 92dbde61e..49f77ce92 100644 --- a/handlers/plivo/plivo_test.go +++ b/handlers/plivo/plivo_test.go @@ -55,70 +55,70 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", - URN: "tel:+250788383383", - Status: "W", - ExternalID: "abc123", - ResponseBody: `{ "message_uuid":["abc123"] }`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "abc123", + MockResponseBody: `{ "message_uuid":["abc123"] }`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic QXV0aElEOkF1dGhUb2tlbg==", }, - RequestBody: `{"src":"2020","dst":"250788383383","text":"Simple Message ☺","url":"https://localhost/c/pl/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status","method":"POST"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"src":"2020","dst":"250788383383","text":"Simple Message ☺","url":"https://localhost/c/pl/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status","method":"POST"}`, + SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+250788383383", - Status: "W", - ExternalID: "abc123", - ResponseBody: `{ "message_uuid":["abc123"] }`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "abc123", + MockResponseBody: `{ "message_uuid":["abc123"] }`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic QXV0aElEOkF1dGhUb2tlbg==", }, - RequestBody: `{"src":"2020","dst":"250788383383","text":"I need to keep adding more things to make it work","url":"https://localhost/c/pl/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status","method":"POST"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"src":"2020","dst":"250788383383","text":"I need to keep adding more things to make it work","url":"https://localhost/c/pl/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status","method":"POST"}`, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", - URN: "tel:+250788383383", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ExternalID: "abc123", - ResponseBody: `{ "message_uuid":["abc123"] }`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + ExpectedExternalID: "abc123", + MockResponseBody: `{ "message_uuid":["abc123"] }`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic QXV0aElEOkF1dGhUb2tlbg==", }, - RequestBody: `{"src":"2020","dst":"250788383383","text":"My pic!\nhttps://foo.bar/image.jpg","url":"https://localhost/c/pl/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status","method":"POST"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"src":"2020","dst":"250788383383","text":"My pic!\nhttps://foo.bar/image.jpg","url":"https://localhost/c/pl/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status","method":"POST"}`, + SendPrep: setSendURL}, {Label: "No External Id", - Text: "No External ID", - URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, - ResponseStatus: 200, - Error: "unable to parse response body from Plivo", - Headers: map[string]string{ + MsgText: "No External ID", + MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, + MockResponseStatus: 200, + ExpectedError: "unable to parse response body from Plivo", + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic QXV0aElEOkF1dGhUb2tlbg==", }, - RequestBody: `{"src":"2020","dst":"250788383383","text":"No External ID","url":"https://localhost/c/pl/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status","method":"POST"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"src":"2020","dst":"250788383383","text":"No External ID","url":"https://localhost/c/pl/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status","method":"POST"}`, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", - URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "failed" }`, - ResponseStatus: 401, - RequestBody: `{"src":"2020","dst":"250788383383","text":"Error Message","url":"https://localhost/c/pl/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status","method":"POST"}`, - SendPrep: setSendURL}, + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{ "error": "failed" }`, + MockResponseStatus: 401, + ExpectedRequestBody: `{"src":"2020","dst":"250788383383","text":"Error Message","url":"https://localhost/c/pl/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status","method":"POST"}`, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/redrabbit/redrabbit_test.go b/handlers/redrabbit/redrabbit_test.go index aa671f231..cbcf7b681 100644 --- a/handlers/redrabbit/redrabbit_test.go +++ b/handlers/redrabbit/redrabbit_test.go @@ -15,10 +15,10 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "SENT", ResponseStatus: 200, - URLParams: map[string]string{ + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "SENT", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{ "LoginName": "Username", "Password": "Password", "Tracking": "1", @@ -29,10 +29,10 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "SENT", ResponseStatus: 200, - URLParams: map[string]string{ + MsgText: "☺", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "SENT", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{ "LoginName": "Username", "Password": "Password", "Tracking": "1", @@ -44,11 +44,11 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Longer Unicode Send", - Text: "This is a message more than seventy characters with some unicode ☺ in them", - URN: "tel:+250788383383", - Status: "W", - ResponseBody: "SENT", ResponseStatus: 200, - URLParams: map[string]string{ + MsgText: "This is a message more than seventy characters with some unicode ☺ in them", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "SENT", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{ "LoginName": "Username", "Password": "Password", "Tracking": "1", @@ -60,11 +60,11 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+250788383383", - Status: "W", - ResponseBody: "SENT", ResponseStatus: 200, - URLParams: map[string]string{ + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "SENT", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{ "LoginName": "Username", "Password": "Password", "Tracking": "1", @@ -76,10 +76,10 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: "SENT", ResponseStatus: 200, - URLParams: map[string]string{ + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: "SENT", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{ "LoginName": "Username", "Password": "Password", "Tracking": "1", @@ -90,9 +90,9 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Sending", URN: "tel:+250788383383", - Status: "E", - ResponseBody: "Error", ResponseStatus: 403, + MsgText: "Error Sending", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: "Error", MockResponseStatus: 403, SendPrep: setSendURL}, } diff --git a/handlers/rocketchat/rocketchat_test.go b/handlers/rocketchat/rocketchat_test.go index facd87537..309d4314e 100644 --- a/handlers/rocketchat/rocketchat_test.go +++ b/handlers/rocketchat/rocketchat_test.go @@ -109,38 +109,38 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var sendTestCases = []handlers.ChannelSendTestCase{ { - Label: "Plain Send", - Text: "Simple Message", - URN: "rocketchat:direct:john.doe#john.doe", - Status: "S", - RequestBody: `{"user":"direct:john.doe","bot":"rocket.cat","text":"Simple Message"}`, - ResponseStatus: 201, - ResponseBody: `{"id":"iNKE8a6k6cjbqWhWd"}`, - ExternalID: "iNKE8a6k6cjbqWhWd", - SendPrep: setSendURL, + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "rocketchat:direct:john.doe#john.doe", + ExpectedStatus: "S", + ExpectedRequestBody: `{"user":"direct:john.doe","bot":"rocket.cat","text":"Simple Message"}`, + MockResponseStatus: 201, + MockResponseBody: `{"id":"iNKE8a6k6cjbqWhWd"}`, + ExpectedExternalID: "iNKE8a6k6cjbqWhWd", + SendPrep: setSendURL, }, { - Label: "Send Attachment", - URN: "rocketchat:livechat:onrMgdKbpX9Qqtvoi", - Attachments: []string{"application/pdf:https://link.to/attachment.pdf"}, - Status: "S", - RequestBody: `{"user":"livechat:onrMgdKbpX9Qqtvoi","bot":"rocket.cat","attachments":[{"type":"application/pdf","url":"https://link.to/attachment.pdf"}]}`, - ResponseStatus: 201, - ResponseBody: `{"id":"iNKE8a6k6cjbqWhWd"}`, - ExternalID: "iNKE8a6k6cjbqWhWd", - SendPrep: setSendURL, + Label: "Send Attachment", + MsgURN: "rocketchat:livechat:onrMgdKbpX9Qqtvoi", + MsgAttachments: []string{"application/pdf:https://link.to/attachment.pdf"}, + ExpectedStatus: "S", + ExpectedRequestBody: `{"user":"livechat:onrMgdKbpX9Qqtvoi","bot":"rocket.cat","attachments":[{"type":"application/pdf","url":"https://link.to/attachment.pdf"}]}`, + MockResponseStatus: 201, + MockResponseBody: `{"id":"iNKE8a6k6cjbqWhWd"}`, + ExpectedExternalID: "iNKE8a6k6cjbqWhWd", + SendPrep: setSendURL, }, { - Label: "Send Text And Attachment", - URN: "rocketchat:direct:john.doe", - Text: "Simple Message", - Attachments: []string{"application/pdf:https://link.to/attachment.pdf"}, - Status: "S", - RequestBody: `{"user":"direct:john.doe","bot":"rocket.cat","text":"Simple Message","attachments":[{"type":"application/pdf","url":"https://link.to/attachment.pdf"}]}`, - ResponseStatus: 201, - ResponseBody: `{"id":"iNKE8a6k6cjbqWhWd"}`, - ExternalID: "iNKE8a6k6cjbqWhWd", - SendPrep: setSendURL, + Label: "Send Text And Attachment", + MsgURN: "rocketchat:direct:john.doe", + MsgText: "Simple Message", + MsgAttachments: []string{"application/pdf:https://link.to/attachment.pdf"}, + ExpectedStatus: "S", + ExpectedRequestBody: `{"user":"direct:john.doe","bot":"rocket.cat","text":"Simple Message","attachments":[{"type":"application/pdf","url":"https://link.to/attachment.pdf"}]}`, + MockResponseStatus: 201, + MockResponseBody: `{"id":"iNKE8a6k6cjbqWhWd"}`, + ExpectedExternalID: "iNKE8a6k6cjbqWhWd", + SendPrep: setSendURL, }, } diff --git a/handlers/shaqodoon/shaqodoon_test.go b/handlers/shaqodoon/shaqodoon_test.go index 31f7c527a..428f2b42f 100644 --- a/handlers/shaqodoon/shaqodoon_test.go +++ b/handlers/shaqodoon/shaqodoon_test.go @@ -56,29 +56,29 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var getSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - URLParams: map[string]string{"msg": "Simple Message", "to": "250788383383", "from": "2020"}, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"msg": "Simple Message", "to": "250788383383", "from": "2020"}, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "0: Accepted for delivery", ResponseStatus: 200, - URLParams: map[string]string{"msg": "☺", "to": "250788383383", "from": "2020"}, - SendPrep: setSendURL}, + MsgText: "☺", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"msg": "☺", "to": "250788383383", "from": "2020"}, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: "1: Unknown channel", ResponseStatus: 401, - URLParams: map[string]string{"msg": `Error Message`, "to": "250788383383"}, - SendPrep: setSendURL}, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: "1: Unknown channel", MockResponseStatus: 401, + ExpectedURLParams: map[string]string{"msg": `Error Message`, "to": "250788383383"}, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `0: Accepted for delivery`, ResponseStatus: 200, - URLParams: map[string]string{"msg": "My pic!\nhttps://foo.bar/image.jpg", "to": "250788383383", "from": "2020"}, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: `0: Accepted for delivery`, MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"msg": "My pic!\nhttps://foo.bar/image.jpg", "to": "250788383383", "from": "2020"}, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index b5965a8c4..9a4236f9c 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -178,41 +178,41 @@ var handleTestCases = []ChannelHandleTestCase{ var defaultSendTestCases = []ChannelSendTestCase{ { - Label: "Plain Send", - Text: "Simple Message", URN: "slack:U0123ABCDEF", - Status: "W", - ResponseBody: `{"ok":true,"channel":"U0123ABCDEF"}`, - ResponseStatus: 200, - RequestBody: `{"channel":"U0123ABCDEF","text":"Simple Message"}`, - SendPrep: setSendUrl, + Label: "Plain Send", + MsgText: "Simple Message", MsgURN: "slack:U0123ABCDEF", + ExpectedStatus: "W", + MockResponseBody: `{"ok":true,"channel":"U0123ABCDEF"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"channel":"U0123ABCDEF","text":"Simple Message"}`, + SendPrep: setSendUrl, }, { - Label: "Unicode Send", - Text: "☺", URN: "slack:U0123ABCDEF", - Status: "W", - ResponseBody: `{"ok":true,"channel":"U0123ABCDEF"}`, - ResponseStatus: 200, - RequestBody: `{"channel":"U0123ABCDEF","text":"☺"}`, - SendPrep: setSendUrl, + Label: "Unicode Send", + MsgText: "☺", MsgURN: "slack:U0123ABCDEF", + ExpectedStatus: "W", + MockResponseBody: `{"ok":true,"channel":"U0123ABCDEF"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"channel":"U0123ABCDEF","text":"☺"}`, + SendPrep: setSendUrl, }, { - Label: "Send Text Auth Error", - Text: "Hello", URN: "slack:U0123ABCDEF", - Status: "E", - ResponseBody: `{"ok":false,"error":"invalid_auth"}`, - ResponseStatus: 200, - RequestBody: `{"channel":"U0123ABCDEF","text":"Hello"}`, - SendPrep: setSendUrl, + Label: "Send Text Auth Error", + MsgText: "Hello", MsgURN: "slack:U0123ABCDEF", + ExpectedStatus: "E", + MockResponseBody: `{"ok":false,"error":"invalid_auth"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"channel":"U0123ABCDEF","text":"Hello"}`, + SendPrep: setSendUrl, }, } var fileSendTestCases = []ChannelSendTestCase{ { - Label: "Send Image", - Text: "", URN: "slack:U0123ABCDEF", - Status: "W", - Attachments: []string{"image/jpeg:https://foo.bar/image.png"}, - Responses: map[MockedRequest]MockedResponse{ + Label: "Send Image", + MsgText: "", MsgURN: "slack:U0123ABCDEF", + ExpectedStatus: "W", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.png"}, + MockResponses: map[MockedRequest]MockedResponse{ { Method: "POST", Path: "/files.upload", @@ -225,11 +225,11 @@ var fileSendTestCases = []ChannelSendTestCase{ SendPrep: setSendUrl, }, { - Label: "Send Image", - Text: "", URN: "slack:U0123ABCDEF", - Status: "W", - Attachments: []string{"image/jpeg:https://foo.bar/image.png"}, - Responses: map[MockedRequest]MockedResponse{ + Label: "Send Image", + MsgText: "", MsgURN: "slack:U0123ABCDEF", + ExpectedStatus: "W", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.png"}, + MockResponses: map[MockedRequest]MockedResponse{ { Method: "POST", Path: "/files.upload", @@ -346,8 +346,8 @@ func mockAttachmentURLs(fileServer *httptest.Server, testCases []ChannelSendTest for i, testCase := range testCases { mockedCase := testCase - for j, attachment := range testCase.Attachments { - mockedCase.Attachments[j] = strings.Replace(attachment, "https://foo.bar", fileServer.URL, 1) + for j, attachment := range testCase.MsgAttachments { + mockedCase.MsgAttachments[j] = strings.Replace(attachment, "https://foo.bar", fileServer.URL, 1) } casesWithMockedUrls[i] = mockedCase } diff --git a/handlers/smscentral/smscentral_test.go b/handlers/smscentral/smscentral_test.go index 9428b8439..e89caf047 100644 --- a/handlers/smscentral/smscentral_test.go +++ b/handlers/smscentral/smscentral_test.go @@ -46,29 +46,29 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - ResponseBody: `[{"id": "1002"}]`, ResponseStatus: 200, - PostParams: map[string]string{"content": "Simple Message", "mobile": "250788383383", "pass": "Password", "user": "Username"}, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: `[{"id": "1002"}]`, MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"content": "Simple Message", "mobile": "250788383383", "pass": "Password", "user": "Username"}, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "tel:+250788383383", - Status: "W", - ResponseBody: `[{"id": "1002"}]`, ResponseStatus: 200, - PostParams: map[string]string{"content": "☺", "mobile": "250788383383", "pass": "Password", "user": "Username"}, - SendPrep: setSendURL}, + MsgText: "☺", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: `[{"id": "1002"}]`, MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"content": "☺", "mobile": "250788383383", "pass": "Password", "user": "Username"}, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `[{ "id": "1002" }]`, ResponseStatus: 200, - PostParams: map[string]string{"content": "My pic!\nhttps://foo.bar/image.jpg", "mobile": "250788383383", "pass": "Password", "user": "Username"}, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: `[{ "id": "1002" }]`, MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"content": "My pic!\nhttps://foo.bar/image.jpg", "mobile": "250788383383", "pass": "Password", "user": "Username"}, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "failed" }`, ResponseStatus: 401, - PostParams: map[string]string{"content": `Error Message`, "mobile": "250788383383", "pass": "Password", "user": "Username"}, - SendPrep: setSendURL}, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, + ExpectedPostParams: map[string]string{"content": `Error Message`, "mobile": "250788383383", "pass": "Password", "user": "Username"}, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/start/start_test.go b/handlers/start/start_test.go index 16df6c114..70a177c1d 100644 --- a/handlers/start/start_test.go +++ b/handlers/start/start_test.go @@ -103,68 +103,68 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", - URN: "tel:+250788383383", - Status: "W", - ExternalID: "380502535130309161501", - ResponseBody: `380502535130309161501Accepted`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "380502535130309161501", + MockResponseBody: `380502535130309161501Accepted`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/xml; charset=utf8", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, - RequestBody: `+250788383383Simple Message ☺`, - SendPrep: setSendURL}, + ExpectedRequestBody: `+250788383383Simple Message ☺`, + SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+250788383383", - Status: "W", - ExternalID: "380502535130309161501", - ResponseBody: `380502535130309161501Accepted`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "380502535130309161501", + MockResponseBody: `380502535130309161501Accepted`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/xml; charset=utf8", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, - RequestBody: `+250788383383I need to keep adding more things to make it work`, - SendPrep: setSendURL}, + ExpectedRequestBody: `+250788383383I need to keep adding more things to make it work`, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - URN: "tel:+250788383383", - Status: "W", - ExternalID: "380502535130309161501", - ResponseBody: `380502535130309161501Accepted`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "My pic!", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "380502535130309161501", + MockResponseBody: `380502535130309161501Accepted`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/xml; charset=utf8", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, - RequestBody: `+250788383383My pic! https://foo.bar/image.jpg`, - SendPrep: setSendURL}, + ExpectedRequestBody: `+250788383383My pic! https://foo.bar/image.jpg`, + SendPrep: setSendURL}, {Label: "Error Response", - Text: "Simple Message ☺", - URN: "tel:+250788383383", - Status: "E", - ExternalID: "", - ResponseBody: `This is an error`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + ExpectedExternalID: "", + MockResponseBody: `This is an error`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/xml; charset=utf8", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, - RequestBody: `+250788383383Simple Message ☺`, - SendPrep: setSendURL}, + ExpectedRequestBody: `+250788383383Simple Message ☺`, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `Error`, ResponseStatus: 401, - Headers: map[string]string{ + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `Error`, MockResponseStatus: 401, + ExpectedHeaders: map[string]string{ "Content-Type": "application/xml; charset=utf8", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, - RequestBody: `+250788383383Error Message`, - SendPrep: setSendURL}, + ExpectedRequestBody: `+250788383383Error Message`, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index c2e11f53f..76e6e1e5e 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -564,96 +564,153 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - Text: "Simple Message", URN: "telegram:12345", - Status: "W", ExternalID: "133", - ResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, ResponseStatus: 200, - PostParams: map[string]string{ + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "telegram:12345", + MockResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{ "text": "Simple Message", "chat_id": "12345", "reply_markup": `{"remove_keyboard":true}`, }, - SendPrep: setSendURL}, - {Label: "Quick Reply", - Text: "Are you happy?", URN: "telegram:12345", QuickReplies: []string{"Yes", "No"}, - Status: "W", ExternalID: "133", - ResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, ResponseStatus: 200, - PostParams: map[string]string{ + ExpectedStatus: "W", + ExpectedExternalID: "133", + SendPrep: setSendURL, + }, + { + Label: "Quick Reply", + MsgText: "Are you happy?", + MsgURN: "telegram:12345", + MsgQuickReplies: []string{"Yes", "No"}, + MockResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{ "text": "Are you happy?", "chat_id": "12345", "reply_markup": `{"keyboard":[[{"text":"Yes"},{"text":"No"}]],"resize_keyboard":true,"one_time_keyboard":true}`, }, - SendPrep: setSendURL}, - {Label: "Quick Reply with multiple attachments", - Text: "Are you happy?", URN: "telegram:12345", QuickReplies: []string{"Yes", "No"}, - Attachments: []string{"application/pdf:https://foo.bar/doc1.pdf", "application/pdf:https://foo.bar/document.pdf"}, - Status: "W", ExternalID: "133", - ResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, ResponseStatus: 200, - PostParams: map[string]string{ + ExpectedStatus: "W", + ExpectedExternalID: "133", + SendPrep: setSendURL, + }, + { + Label: "Quick Reply with multiple attachments", + MsgText: "Are you happy?", + MsgURN: "telegram:12345", + MsgQuickReplies: []string{"Yes", "No"}, + MsgAttachments: []string{"application/pdf:https://foo.bar/doc1.pdf", "application/pdf:https://foo.bar/document.pdf"}, + MockResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{ "chat_id": "12345", "document": "https://foo.bar/document.pdf", "reply_markup": `{"keyboard":[[{"text":"Yes"},{"text":"No"}]],"resize_keyboard":true,"one_time_keyboard":true}`, }, - SendPrep: setSendURL}, - - {Label: "Unicode Send", - Text: "☺", URN: "telegram:12345", - Status: "W", ExternalID: "133", - ResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, ResponseStatus: 200, - PostParams: map[string]string{"text": "☺", "chat_id": "12345"}, - SendPrep: setSendURL}, - {Label: "Error", - Text: "Error", URN: "telegram:12345", - Status: "E", - ResponseBody: `{ "ok": false }`, ResponseStatus: 403, - PostParams: map[string]string{"text": `Error`, "chat_id": "12345"}, - SendPrep: setSendURL}, - {Label: "Stopped Contact Code", - Text: "Stopped Contact", URN: "telegram:12345", - Status: "F", - ResponseBody: `{ "ok": false, "error_code":403, "description":"Forbidden: bot was blocked by the user"}`, ResponseStatus: 403, - PostParams: map[string]string{"text": `Stopped Contact`, "chat_id": "12345"}, - SendPrep: setSendURL, - Stopped: true}, - {Label: "Should not stop other error", - Text: "Simple Message", URN: "telegram:12345", - Status: "E", - ResponseBody: `{ "ok": true }`, ResponseStatus: 200, - PostParams: map[string]string{ + ExpectedStatus: "W", + ExpectedExternalID: "133", + SendPrep: setSendURL, + }, + + { + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "telegram:12345", + MockResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"text": "☺", "chat_id": "12345"}, + ExpectedStatus: "W", + ExpectedExternalID: "133", + SendPrep: setSendURL, + }, + { + Label: "Error", + MsgText: "Error", + MsgURN: "telegram:12345", + MockResponseBody: `{ "ok": false }`, + MockResponseStatus: 403, + ExpectedPostParams: map[string]string{"text": `Error`, "chat_id": "12345"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Stopped Contact Code", + MsgText: "Stopped Contact", + MsgURN: "telegram:12345", + MockResponseBody: `{ "ok": false, "error_code":403, "description":"Forbidden: bot was blocked by the user"}`, + MockResponseStatus: 403, + ExpectedPostParams: map[string]string{"text": `Stopped Contact`, "chat_id": "12345"}, + ExpectedStatus: "F", + ExpectedStopEvent: true, + SendPrep: setSendURL, + }, + { + Label: "Should not stop other error", + MsgText: "Simple Message", + MsgURN: "telegram:12345", + MockResponseBody: `{ "ok": true }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{ "text": "Simple Message", "chat_id": "12345", "reply_markup": `{"remove_keyboard":true}`, }, - SendPrep: setSendURL, - Stopped: false}, - {Label: "Send Photo", - Text: "My pic!", URN: "telegram:12345", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, ResponseStatus: 200, - PostParams: map[string]string{"caption": "My pic!", "chat_id": "12345", "photo": "https://foo.bar/image.jpg"}, - SendPrep: setSendURL}, - {Label: "Send Video", - Text: "My vid!", URN: "telegram:12345", Attachments: []string{"video/mpeg:https://foo.bar/video.mpeg"}, - Status: "W", - ResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, ResponseStatus: 200, - PostParams: map[string]string{"caption": "My vid!", "chat_id": "12345", "video": "https://foo.bar/video.mpeg"}, - SendPrep: setSendURL}, - {Label: "Send Audio", - Text: "My audio!", URN: "telegram:12345", Attachments: []string{"audio/mp3:https://foo.bar/audio.mp3"}, - Status: "W", - ResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, ResponseStatus: 200, - PostParams: map[string]string{"caption": "My audio!", "chat_id": "12345", "audio": "https://foo.bar/audio.mp3"}, - SendPrep: setSendURL}, - {Label: "Send Document", - Text: "My document!", URN: "telegram:12345", Attachments: []string{"application/pdf:https://foo.bar/document.pdf"}, - Status: "W", - ResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, ResponseStatus: 200, - PostParams: map[string]string{"caption": "My document!", "chat_id": "12345", "document": "https://foo.bar/document.pdf"}, - SendPrep: setSendURL}, - {Label: "Unknown Attachment", - Text: "My pic!", URN: "telegram:12345", Attachments: []string{"unknown/foo:https://foo.bar/unknown.foo"}, - Status: "E", - SendPrep: setSendURL}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Send Photo", + MsgText: "My pic!", + MsgURN: "telegram:12345", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"caption": "My pic!", "chat_id": "12345", "photo": "https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Video", + MsgText: "My vid!", + MsgURN: "telegram:12345", + MsgAttachments: []string{"video/mpeg:https://foo.bar/video.mpeg"}, + MockResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"caption": "My vid!", "chat_id": "12345", "video": "https://foo.bar/video.mpeg"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Audio", + MsgText: "My audio!", + MsgURN: "telegram:12345", + MsgAttachments: []string{"audio/mp3:https://foo.bar/audio.mp3"}, + MockResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"caption": "My audio!", "chat_id": "12345", "audio": "https://foo.bar/audio.mp3"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Document", + MsgText: "My document!", + MsgURN: "telegram:12345", + MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, + MockResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"caption": "My document!", "chat_id": "12345", "document": "https://foo.bar/document.pdf"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Unknown Attachment", + MsgText: "My pic!", + MsgURN: "telegram:12345", + MsgAttachments: []string{"unknown/foo:https://foo.bar/unknown.foo"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/telesom/telesom_test.go b/handlers/telesom/telesom_test.go index c5cc9261d..2cd9cc8b0 100644 --- a/handlers/telesom/telesom_test.go +++ b/handlers/telesom/telesom_test.go @@ -52,33 +52,33 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+252788383383", - Status: "W", - ResponseBody: "Success", ResponseStatus: 200, - URLParams: map[string]string{"msg": "Simple Message", "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "D69BB824F88F20482B94ECF3822EBD84"}, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "tel:+252788383383", + ExpectedStatus: "W", + MockResponseBody: "Success", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"msg": "Simple Message", "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "D69BB824F88F20482B94ECF3822EBD84"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "tel:+252788383383", - Status: "W", - ResponseBody: "Success", ResponseStatus: 200, - URLParams: map[string]string{"msg": "☺", "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "60421A7D99BD79FE02697D567315AD0E"}, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + MsgText: "☺", MsgURN: "tel:+252788383383", + ExpectedStatus: "W", + MockResponseBody: "Success", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"msg": "☺", "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "60421A7D99BD79FE02697D567315AD0E"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+252788383383", - Status: "E", - ResponseBody: "error", ResponseStatus: 401, - URLParams: map[string]string{"msg": `Error Message`, "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "3F1E492B2186551570F24C2F07D5D7E2"}, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + MsgText: "Error Message", MsgURN: "tel:+252788383383", + ExpectedStatus: "E", + MockResponseBody: "error", MockResponseStatus: 401, + ExpectedURLParams: map[string]string{"msg": `Error Message`, "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "3F1E492B2186551570F24C2F07D5D7E2"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+252788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `Success`, ResponseStatus: 200, - URLParams: map[string]string{"msg": "My pic!\nhttps://foo.bar/image.jpg", "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "DBE569579FD899628C17254ECCE15DB7"}, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+252788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: `Success`, MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"msg": "My pic!\nhttps://foo.bar/image.jpg", "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "DBE569579FD899628C17254ECCE15DB7"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/test.go b/handlers/test.go index d420c5990..1a789f02e 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -78,39 +78,37 @@ type MockedResponse struct { // ChannelSendTestCase defines the test values for a particular test case type ChannelSendTestCase struct { - Label string - - Text string - URN string - URNAuth string - Attachments []string - QuickReplies []string - Topic string - HighPriority bool - ResponseToExternalID string - Metadata json.RawMessage - Flow *courier.FlowReference - - ResponseStatus int - ResponseBody string - Responses map[MockedRequest]MockedResponse - - Path string - URLParams map[string]string - PostParams map[string]string - RequestBody string - Headers map[string]string - - Error string - Status string - ExternalID string - - Stopped bool - - ContactURNs map[string]bool - + Label string SendPrep SendPrepFunc - NewURN string + + MsgText string + MsgURN string + MsgURNAuth string + MsgAttachments []string + MsgQuickReplies []string + MsgTopic string + MsgHighPriority bool + MsgResponseToExternalID string + MsgMetadata json.RawMessage + MsgFlow *courier.FlowReference + + MockResponseStatus int + MockResponseBody string + MockResponses map[MockedRequest]MockedResponse + + ExpectedRequestPath string + ExpectedURLParams map[string]string + ExpectedPostParams map[string]string + ExpectedRequestBody string + ExpectedHeaders map[string]string + + ExpectedError string + ExpectedStatus string + ExpectedExternalID string + + ExpectedStopEvent bool + ExpectedContactURNs map[string]bool + ExpectedNewURN string } // Sp is a utility method to get the pointer to the passed in string @@ -223,19 +221,19 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour t.Run(testCase.Label, func(t *testing.T) { require := require.New(t) - msg := mb.NewOutgoingMsg(channel, courier.NewMsgID(10), urns.URN(testCase.URN), testCase.Text, testCase.HighPriority, testCase.QuickReplies, testCase.Topic, testCase.ResponseToExternalID) + msg := mb.NewOutgoingMsg(channel, courier.NewMsgID(10), urns.URN(testCase.MsgURN), testCase.MsgText, testCase.MsgHighPriority, testCase.MsgQuickReplies, testCase.MsgTopic, testCase.MsgResponseToExternalID) - for _, a := range testCase.Attachments { + for _, a := range testCase.MsgAttachments { msg.WithAttachment(a) } - if testCase.URNAuth != "" { - msg.WithURNAuth(testCase.URNAuth) + if testCase.MsgURNAuth != "" { + msg.WithURNAuth(testCase.MsgURNAuth) } - if len(testCase.Metadata) > 0 { - msg.WithMetadata(testCase.Metadata) + if len(testCase.MsgMetadata) > 0 { + msg.WithMetadata(testCase.MsgMetadata) } - if testCase.Flow != nil { - msg.WithFlow(testCase.Flow) + if testCase.MsgFlow != nil { + msg.WithFlow(testCase.MsgFlow) } var testRequest *http.Request @@ -243,13 +241,13 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour body, _ := ioutil.ReadAll(r.Body) testRequest = httptest.NewRequest(r.Method, r.URL.String(), bytes.NewBuffer(body)) testRequest.Header = r.Header - if (len(testCase.Responses)) == 0 { - w.WriteHeader(testCase.ResponseStatus) - w.Write([]byte(testCase.ResponseBody)) + if (len(testCase.MockResponses)) == 0 { + w.WriteHeader(testCase.MockResponseStatus) + w.Write([]byte(testCase.MockResponseBody)) } else { - require.Zero(testCase.ResponseStatus, "ResponseStatus should not be used when using testcase.Responses") - require.Zero(testCase.ResponseBody, "ResponseBody should not be used when using testcase.Responses") - for mockRequest, mockResponse := range testCase.Responses { + require.Zero(testCase.MockResponseStatus, "ResponseStatus should not be used when using testcase.Responses") + require.Zero(testCase.MockResponseBody, "ResponseBody should not be used when using testcase.Responses") + for mockRequest, mockResponse := range testCase.MockResponses { bodyStr := string(body)[:] if mockRequest.Method == r.Method && mockRequest.Path == r.URL.Path && mockRequest.RawQuery == r.URL.RawQuery && (mockRequest.Body == bodyStr || (mockRequest.BodyContains != "" && strings.Contains(bodyStr, mockRequest.BodyContains))) { w.WriteHeader(mockResponse.Status) @@ -271,73 +269,73 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour status, err := handler.SendMsg(ctx, msg) cancel() - if testCase.Error != "" { + if testCase.ExpectedError != "" { if err == nil { - t.Errorf("expected error: %s", testCase.Error) + t.Errorf("expected error: %s", testCase.ExpectedError) } else { - require.Equal(testCase.Error, err.Error()) + require.Equal(testCase.ExpectedError, err.Error()) } } else if err != nil { t.Errorf("unexpected error: %s", err.Error()) } - if testCase.Path != "" { + if testCase.ExpectedRequestPath != "" { require.NotNil(testRequest, "path should not be nil") - require.Equal(testCase.Path, testRequest.URL.Path) + require.Equal(testCase.ExpectedRequestPath, testRequest.URL.Path) } - if testCase.URLParams != nil { + if testCase.ExpectedURLParams != nil { require.NotNil(testRequest) - for k, v := range testCase.URLParams { + for k, v := range testCase.ExpectedURLParams { value := testRequest.URL.Query().Get(k) require.Equal(v, value, fmt.Sprintf("%s not equal", k)) } } - if testCase.PostParams != nil { + if testCase.ExpectedPostParams != nil { require.NotNil(testRequest, "post body should not be nil") - for k, v := range testCase.PostParams { + for k, v := range testCase.ExpectedPostParams { value := testRequest.PostFormValue(k) require.Equal(v, value) } } - if testCase.RequestBody != "" { + if testCase.ExpectedRequestBody != "" { require.NotNil(testRequest, "request body should not be nil") value, _ := ioutil.ReadAll(testRequest.Body) - require.Equal(testCase.RequestBody, strings.Trim(string(value), "\n")) + require.Equal(testCase.ExpectedRequestBody, strings.Trim(string(value), "\n")) } - if (len(testCase.Responses)) != 0 { - require.Equal(mockRRCount, len(testCase.Responses)) + if (len(testCase.MockResponses)) != 0 { + require.Equal(mockRRCount, len(testCase.MockResponses)) } - if testCase.Headers != nil { + if testCase.ExpectedHeaders != nil { require.NotNil(testRequest, "headers should not be nil") - for k, v := range testCase.Headers { + for k, v := range testCase.ExpectedHeaders { value := testRequest.Header.Get(k) require.Equal(v, value) } } - if testCase.ExternalID != "" { - require.Equal(testCase.ExternalID, status.ExternalID()) + if testCase.ExpectedExternalID != "" { + require.Equal(testCase.ExpectedExternalID, status.ExternalID()) } - if testCase.Status != "" { + if testCase.ExpectedStatus != "" { require.NotNil(status, "status should not be nil") - require.Equal(testCase.Status, string(status.Status())) + require.Equal(testCase.ExpectedStatus, string(status.Status())) } - if testCase.Stopped { + if testCase.ExpectedStopEvent { evt, err := mb.GetLastChannelEvent() require.NoError(err) require.Equal(courier.StopContact, evt.EventType()) } - if testCase.ContactURNs != nil { + if testCase.ExpectedContactURNs != nil { var contactUUID courier.ContactUUID - for urn, shouldBePresent := range testCase.ContactURNs { + for urn, shouldBePresent := range testCase.ExpectedContactURNs { contact, _ := mb.GetContact(ctx, channel, urns.URN(urn), "", "") if contactUUID == courier.NilContactUUID && shouldBePresent { contactUUID = contact.UUID() @@ -351,10 +349,10 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour } } - if testCase.NewURN != "" { + if testCase.ExpectedNewURN != "" { old, new := status.UpdatedURN() - require.Equal(urns.URN(testCase.URN), old) - require.Equal(urns.URN(testCase.NewURN), new) + require.Equal(urns.URN(testCase.MsgURN), old) + require.Equal(urns.URN(testCase.ExpectedNewURN), new) } }) } diff --git a/handlers/thinq/thinq_test.go b/handlers/thinq/thinq_test.go index 5ef92b15f..af01fe9c2 100644 --- a/handlers/thinq/thinq_test.go +++ b/handlers/thinq/thinq_test.go @@ -50,35 +50,35 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var sendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", URN: "tel:+12067791234", - Status: "W", ExternalID: "1002", - ResponseBody: `{ "guid": "1002" }`, ResponseStatus: 200, - Headers: map[string]string{"Authorization": "Basic dXNlcjE6c2VzYW1l"}, - RequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"Simple Message ☺"}`, - SendPrep: setSendURL}, + MsgText: "Simple Message ☺", MsgURN: "tel:+12067791234", + ExpectedStatus: "W", ExpectedExternalID: "1002", + MockResponseBody: `{ "guid": "1002" }`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Authorization": "Basic dXNlcjE6c2VzYW1l"}, + ExpectedRequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"Simple Message ☺"}`, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+12067791234", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", ExternalID: "1002", - ResponseBody: `{ "guid": "1002" }`, ResponseStatus: 200, - RequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"My pic!"}`, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+12067791234", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", ExpectedExternalID: "1002", + MockResponseBody: `{ "guid": "1002" }`, MockResponseStatus: 200, + ExpectedRequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"My pic!"}`, + SendPrep: setSendURL}, {Label: "Only Attachment", - Text: "", URN: "tel:+12067791234", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", ExternalID: "1002", - ResponseBody: `{ "guid": "1002" }`, ResponseStatus: 200, + MsgText: "", MsgURN: "tel:+12067791234", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", ExpectedExternalID: "1002", + MockResponseBody: `{ "guid": "1002" }`, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "No External ID", - Text: "No External ID", URN: "tel:+12067791234", - Status: "E", - ResponseBody: `{}`, ResponseStatus: 200, - RequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"No External ID"}`, - SendPrep: setSendURL}, + MsgText: "No External ID", MsgURN: "tel:+12067791234", + ExpectedStatus: "E", + MockResponseBody: `{}`, MockResponseStatus: 200, + ExpectedRequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"No External ID"}`, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+12067791234", - Status: "E", - ResponseBody: `{ "error": "failed" }`, ResponseStatus: 401, - RequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"Error Message"}`, - SendPrep: setSendURL}, + MsgText: "Error Message", MsgURN: "tel:+12067791234", + ExpectedStatus: "E", + MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, + ExpectedRequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"Error Message"}`, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index 9aa4f0656..c44b29b16 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -290,227 +290,357 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - Text: "Simple Message ☺", URN: "tel:+250788383383", - Status: "W", ExternalID: "1002", - ResponseBody: `{ "sid": "1002" }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "Simple Message ☺", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - Path: "/2010-04-01/Accounts/accountSID/Messages.json", - Headers: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - SendPrep: setSendURL}, - {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+250788383383", - Status: "W", ExternalID: "1002", - ResponseBody: `{ "sid": "1002" }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "I need to keep adding more things to make it work", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - Path: "/2010-04-01/Accounts/accountSID/Messages.json", - Headers: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - SendPrep: setSendURL}, - {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "out of credits" }`, ResponseStatus: 401, - PostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - SendPrep: setSendURL}, - {Label: "Error Code", - Text: "Error Code", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "code": 1001 }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - SendPrep: setSendURL}, - {Label: "Stopped Contact Code", - Text: "Stopped Contact", URN: "tel:+250788383383", - Status: "F", - ResponseBody: `{ "code": 21610 }`, ResponseStatus: 400, - PostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - SendPrep: setSendURL, - Stopped: true}, - {Label: "No SID", - Text: "No SID", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - SendPrep: setSendURL}, - {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `{ "sid": "1002" }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "My pic!", "To": "+250788383383", "MediaUrl": "https://foo.bar/image.jpg", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - SendPrep: setSendURL}, + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "sid": "1002" }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "Simple Message ☺", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedRequestPath: "/2010-04-01/Accounts/accountSID/Messages.json", + ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Long Send", + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "sid": "1002" }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "I need to keep adding more things to make it work", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedRequestPath: "/2010-04-01/Accounts/accountSID/Messages.json", + ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "error": "out of credits" }`, + MockResponseStatus: 401, + ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error Code", + MsgText: "Error Code", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "code": 1001 }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Stopped Contact Code", + MsgText: "Stopped Contact", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "code": 21610 }`, + MockResponseStatus: 400, + ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedStopEvent: true, + ExpectedStatus: "F", + SendPrep: setSendURL, + }, + { + Label: "No SID", + MsgText: "No SID", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{ "sid": "1002" }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "My pic!", "To": "+250788383383", "MediaUrl": "https://foo.bar/image.jpg", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } var tmsDefaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - Text: "Simple Message ☺", URN: "tel:+250788383383", - Status: "W", ExternalID: "1002", - ResponseBody: `{ "sid": "1002" }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "Simple Message ☺", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, - Path: "/2010-04-01/Accounts/accountSID/Messages.json", - Headers: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - SendPrep: setSendURL}, - {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+250788383383", - Status: "W", ExternalID: "1002", - ResponseBody: `{ "sid": "1002" }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "I need to keep adding more things to make it work", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, - Path: "/2010-04-01/Accounts/accountSID/Messages.json", - Headers: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - SendPrep: setSendURL}, - {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "out of credits" }`, ResponseStatus: 401, - PostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, - SendPrep: setSendURL}, - {Label: "Error Code", - Text: "Error Code", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "code": 1001 }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, - SendPrep: setSendURL}, - {Label: "Stopped Contact Code", - Text: "Stopped Contact", URN: "tel:+250788383383", - Status: "F", - ResponseBody: `{ "code": 21610 }`, ResponseStatus: 400, - PostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, - SendPrep: setSendURL, - Stopped: true}, - {Label: "No SID", - Text: "No SID", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, - SendPrep: setSendURL}, - {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `{ "sid": "1002" }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "My pic!", "To": "+250788383383", "MediaUrl": "https://foo.bar/image.jpg", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, - SendPrep: setSendURL}, + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "sid": "1002" }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "Simple Message ☺", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, + ExpectedRequestPath: "/2010-04-01/Accounts/accountSID/Messages.json", + ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Long Send", + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "sid": "1002" }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "I need to keep adding more things to make it work", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, + ExpectedRequestPath: "/2010-04-01/Accounts/accountSID/Messages.json", + ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "error": "out of credits" }`, + MockResponseStatus: 401, + ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error Code", + MsgText: "Error Code", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "code": 1001 }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Stopped Contact Code", + MsgText: "Stopped Contact", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "code": 21610 }`, + MockResponseStatus: 400, + ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, + ExpectedStopEvent: true, + ExpectedStatus: "F", + SendPrep: setSendURL, + }, + { + Label: "No SID", + MsgText: "No SID", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{ "sid": "1002" }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "My pic!", "To": "+250788383383", "MediaUrl": "https://foo.bar/image.jpg", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } var twDefaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - Text: "Simple Message ☺", URN: "tel:+250788383383", - Status: "W", ExternalID: "1002", - ResponseBody: `{ "sid": "1002" }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "Simple Message ☺", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - Path: "/2010-04-01/Accounts/accountSID/Messages.json", - Headers: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - SendPrep: setSendURL}, - {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+250788383383", - Status: "W", ExternalID: "1002", - ResponseBody: `{ "sid": "1002" }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "I need to keep adding more things to make it work", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - Path: "/2010-04-01/Accounts/accountSID/Messages.json", - Headers: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - SendPrep: setSendURL}, - {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "out of credits" }`, ResponseStatus: 401, - PostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - SendPrep: setSendURL}, - {Label: "Error Code", - Text: "Error Code", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "code": 1001 }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - SendPrep: setSendURL}, - {Label: "Stopped Contact Code", - Text: "Stopped Contact", URN: "tel:+250788383383", - Status: "F", - ResponseBody: `{ "code": 21610 }`, ResponseStatus: 400, - PostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - SendPrep: setSendURL, - Stopped: true}, - {Label: "No SID", - Text: "No SID", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - SendPrep: setSendURL}, - {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `{ "sid": "1002" }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "My pic!", "To": "+250788383383", "MediaUrl": "https://foo.bar/image.jpg", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - SendPrep: setSendURL}, + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "sid": "1002" }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "Simple Message ☺", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedRequestPath: "/2010-04-01/Accounts/accountSID/Messages.json", + ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Long Send", + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "sid": "1002" }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "I need to keep adding more things to make it work", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedRequestPath: "/2010-04-01/Accounts/accountSID/Messages.json", + ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "error": "out of credits" }`, + MockResponseStatus: 401, + ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error Code", + MsgText: "Error Code", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "code": 1001 }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Stopped Contact Code", + MsgText: "Stopped Contact", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "code": 21610 }`, + MockResponseStatus: 400, + ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedStatus: "F", + ExpectedStopEvent: true, + SendPrep: setSendURL, + }, + { + Label: "No SID", + MsgText: "No SID", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{ "sid": "1002" }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "My pic!", "To": "+250788383383", "MediaUrl": "https://foo.bar/image.jpg", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } var swSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - Text: "Simple Message ☺", URN: "tel:+250788383383", - Status: "W", ExternalID: "1002", - ResponseBody: `{ "sid": "1002" }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "Simple Message ☺", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - Path: "/2010-04-01/Accounts/accountSID/Messages.json", - Headers: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - SendPrep: setSendURL}, - {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+250788383383", - Status: "W", ExternalID: "1002", - ResponseBody: `{ "sid": "1002" }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "I need to keep adding more things to make it work", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - Path: "/2010-04-01/Accounts/accountSID/Messages.json", - Headers: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - SendPrep: setSendURL}, - {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "out of credits" }`, ResponseStatus: 401, - PostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - SendPrep: setSendURL}, - {Label: "Error Code", - Text: "Error Code", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "code": 1001 }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - SendPrep: setSendURL}, - {Label: "Stopped Contact Code", - Text: "Stopped Contact", URN: "tel:+250788383383", - Status: "F", - ResponseBody: `{ "code": 21610 }`, ResponseStatus: 400, - PostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - SendPrep: setSendURL, - Stopped: true}, - {Label: "No SID", - Text: "No SID", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - SendPrep: setSendURL}, - {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: `{ "sid": "1002" }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "My pic!", "To": "+250788383383", "MediaUrl": "https://foo.bar/image.jpg", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - SendPrep: setSendURL}, + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "sid": "1002" }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "Simple Message ☺", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedRequestPath: "/2010-04-01/Accounts/accountSID/Messages.json", + ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Long Send", + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "sid": "1002" }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "I need to keep adding more things to make it work", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedRequestPath: "/2010-04-01/Accounts/accountSID/Messages.json", + ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "error": "out of credits" }`, + MockResponseStatus: 401, + ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error Code", + MsgText: "Error Code", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "code": 1001 }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Stopped Contact Code", + MsgText: "Stopped Contact", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "code": 21610 }`, + MockResponseStatus: 400, + ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedStatus: "F", + ExpectedStopEvent: true, + SendPrep: setSendURL, + }, + { + Label: "No SID", + MsgText: "No SID", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{ "sid": "1002" }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "My pic!", "To": "+250788383383", "MediaUrl": "https://foo.bar/image.jpg", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } var waSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - Text: "Simple Message ☺", URN: "whatsapp:250788383383", - Status: "W", ExternalID: "1002", - ResponseBody: `{ "sid": "1002" }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "Simple Message ☺", "To": "whatsapp:+250788383383", "From": "whatsapp:+12065551212", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - Headers: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - SendPrep: setSendURL}, + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "whatsapp:250788383383", + MockResponseBody: `{ "sid": "1002" }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "Simple Message ☺", "To": "whatsapp:+250788383383", "From": "whatsapp:+12065551212", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, } var twaSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - Text: "Simple Message ☺", URN: "whatsapp:250788383383", - Status: "W", ExternalID: "1002", - ResponseBody: `{ "sid": "1002" }`, ResponseStatus: 200, - PostParams: map[string]string{"Body": "Simple Message ☺", "To": "whatsapp:+250788383383", "From": "whatsapp:+12065551212", "StatusCallback": "https://localhost/c/twa/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - Headers: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - SendPrep: setSendURL}, + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "whatsapp:250788383383", + MockResponseBody: `{ "sid": "1002" }`, + MockResponseStatus: 200, + ExpectedPostParams: map[string]string{"Body": "Simple Message ☺", "To": "whatsapp:+250788383383", "From": "whatsapp:+12065551212", "StatusCallback": "https://localhost/c/twa/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/twitter/twitter_test.go b/handlers/twitter/twitter_test.go index 490da251b..6b27593a0 100644 --- a/handlers/twitter/twitter_test.go +++ b/handlers/twitter/twitter_test.go @@ -194,24 +194,24 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "twitterid:12345", - Status: "W", ExternalID: "133", - Path: "/1.1/direct_messages/events/new.json", - ResponseBody: `{"event": { "id": "133"}}`, ResponseStatus: 200, - RequestBody: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"Simple Message"}}}}`, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "twitterid:12345", + ExpectedStatus: "W", ExpectedExternalID: "133", + ExpectedRequestPath: "/1.1/direct_messages/events/new.json", + MockResponseBody: `{"event": { "id": "133"}}`, MockResponseStatus: 200, + ExpectedRequestBody: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"Simple Message"}}}}`, + SendPrep: setSendURL}, {Label: "Quick Reply", - Text: "Are you happy?", URN: "twitterid:12345", QuickReplies: []string{"Yes", "No, but a really long no that is unreasonably long"}, - Status: "W", ExternalID: "133", - ResponseBody: `{"event": { "id": "133"}}`, ResponseStatus: 200, - RequestBody: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"Are you happy?","quick_reply":{"type":"options","options":[{"label":"Yes"},{"label":"No, but a really long no that is unr"}]}}}}}`, - SendPrep: setSendURL}, + MsgText: "Are you happy?", MsgURN: "twitterid:12345", MsgQuickReplies: []string{"Yes", "No, but a really long no that is unreasonably long"}, + ExpectedStatus: "W", ExpectedExternalID: "133", + MockResponseBody: `{"event": { "id": "133"}}`, MockResponseStatus: 200, + ExpectedRequestBody: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"Are you happy?","quick_reply":{"type":"options","options":[{"label":"Yes"},{"label":"No, but a really long no that is unr"}]}}}}}`, + SendPrep: setSendURL}, {Label: "Image Send", - Text: "document caption", - URN: "twitterid:12345", - Status: "W", ExternalID: "133", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Responses: map[MockedRequest]MockedResponse{ + MsgText: "document caption", + MsgURN: "twitterid:12345", + ExpectedStatus: "W", ExpectedExternalID: "133", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponses: map[MockedRequest]MockedResponse{ MockedRequest{ Method: "POST", Path: "/1.1/media/upload.json", @@ -265,11 +265,11 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL, }, {Label: "Image Send", - Text: "document caption", - URN: "twitterid:12345", - Status: "W", ExternalID: "133", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Responses: map[MockedRequest]MockedResponse{ + MsgText: "document caption", + MsgURN: "twitterid:12345", + ExpectedStatus: "W", ExpectedExternalID: "133", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponses: map[MockedRequest]MockedResponse{ MockedRequest{ Method: "POST", Path: "/1.1/media/upload.json", @@ -323,11 +323,11 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL, }, {Label: "Video Send", - Text: "document caption", - URN: "twitterid:12345", - Status: "W", ExternalID: "133", - Attachments: []string{"video/mp4:https://foo.bar/video.mp4"}, - Responses: map[MockedRequest]MockedResponse{ + MsgText: "document caption", + MsgURN: "twitterid:12345", + ExpectedStatus: "W", ExpectedExternalID: "133", + MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, + MockResponses: map[MockedRequest]MockedResponse{ MockedRequest{ Method: "POST", Path: "/1.1/media/upload.json", @@ -382,11 +382,11 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL, }, {Label: "Send Audio", - Text: "My audio!", - URN: "twitterid:12345", - Status: "W", ExternalID: "133", - Attachments: []string{"audio/mp3:https://foo.bar/audio.mp3"}, - Responses: map[MockedRequest]MockedResponse{ + MsgText: "My audio!", + MsgURN: "twitterid:12345", + ExpectedStatus: "W", ExpectedExternalID: "133", + MsgAttachments: []string{"audio/mp3:https://foo.bar/audio.mp3"}, + MockResponses: map[MockedRequest]MockedResponse{ MockedRequest{ Method: "POST", Path: "/1.1/direct_messages/events/new.json", @@ -406,14 +406,14 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "ID Error", - Text: "ID Error", URN: "twitterid:12345", - Status: "E", - ResponseBody: `{ "is_error": true }`, ResponseStatus: 200, + MsgText: "ID Error", MsgURN: "twitterid:12345", + ExpectedStatus: "E", + MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Error", - Text: "Error", URN: "twitterid:12345", - Status: "E", - ResponseBody: `{ "is_error": true }`, ResponseStatus: 403, + MsgText: "Error", MsgURN: "twitterid:12345", + ExpectedStatus: "E", + MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 403, SendPrep: setSendURL}, } @@ -421,12 +421,12 @@ func mockAttachmentURLs(mediaServer *httptest.Server, testCases []ChannelSendTes casesWithMockedUrls := make([]ChannelSendTestCase, len(testCases)) for i, testCase := range testCases { mockedCase := testCase - for j, attachment := range testCase.Attachments { + for j, attachment := range testCase.MsgAttachments { parts := strings.SplitN(attachment, ":", 2) mimeType := parts[0] urlString := parts[1] parsedURL, _ := url.Parse(urlString) - mockedCase.Attachments[j] = fmt.Sprintf("%s:%s%s", mimeType, mediaServer.URL, parsedURL.Path) + mockedCase.MsgAttachments[j] = fmt.Sprintf("%s:%s%s", mimeType, mediaServer.URL, parsedURL.Path) } casesWithMockedUrls[i] = mockedCase } diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index 70976a0c5..ca6b313a8 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -30,14 +30,14 @@ func buildMockAttachmentService(testCases []ChannelSendTestCase) *httptest.Serve // update our tests media urls for c := range testCases { - if len(testCases[c].Attachments) > 0 { - for i, a := range testCases[c].Attachments { + if len(testCases[c].MsgAttachments) > 0 { + for i, a := range testCases[c].MsgAttachments { mediaType, mediaURL := SplitAttachment(a) parts := strings.Split(mediaURL, "/") - testCases[c].Attachments[i] = fmt.Sprintf("%s:%s/%s", mediaType, server.URL, parts[len(parts)-1]) + testCases[c].MsgAttachments[i] = fmt.Sprintf("%s:%s/%s", mediaType, server.URL, parts[len(parts)-1]) } } - testCases[c].RequestBody = strings.Replace(testCases[c].RequestBody, "{{ SERVER_URL }}", server.URL, -1) + testCases[c].ExpectedRequestBody = strings.Replace(testCases[c].ExpectedRequestBody, "{{ SERVER_URL }}", server.URL, -1) } return server @@ -45,134 +45,134 @@ func buildMockAttachmentService(testCases []ChannelSendTestCase) *httptest.Serve var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "viber:xy5/5y6O81+/kbWHpLhBoA==", - Status: "W", ResponseStatus: 200, - ResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - Headers: map[string]string{ + MsgText: "Simple Message", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + ExpectedStatus: "W", MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, + SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "viber:xy5/5y6O81+/kbWHpLhBoA==", - Status: "W", ResponseStatus: 200, - ResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - Headers: map[string]string{ + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + ExpectedStatus: "W", MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"I need to keep adding more things to make it work","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"I need to keep adding more things to make it work","type":"text","tracking_data":"10"}`, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "viber:xy5/5y6O81+/kbWHpLhBoA==", - Status: "W", ResponseStatus: 200, - ResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - Headers: map[string]string{ + MsgText: "☺", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + ExpectedStatus: "W", MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"☺","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"☺","type":"text","tracking_data":"10"}`, + SendPrep: setSendURL}, {Label: "Quick Reply", - Text: "Are you happy?", URN: "viber:xy5/5y6O81+/kbWHpLhBoA==", QuickReplies: []string{"Yes", "No"}, - Status: "W", ResponseStatus: 200, - ResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - Headers: map[string]string{ + MsgText: "Are you happy?", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", MsgQuickReplies: []string{"Yes", "No"}, + ExpectedStatus: "W", MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Are you happy?","type":"text","tracking_data":"10","keyboard":{"Type":"keyboard","DefaultHeight":false,"Buttons":[{"ActionType":"reply","ActionBody":"Yes","Text":"Yes","TextSize":"regular","Columns":"3"},{"ActionType":"reply","ActionBody":"No","Text":"No","TextSize":"regular","Columns":"3"}]}}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Are you happy?","type":"text","tracking_data":"10","keyboard":{"Type":"keyboard","DefaultHeight":false,"Buttons":[{"ActionType":"reply","ActionBody":"Yes","Text":"Yes","TextSize":"regular","Columns":"3"},{"ActionType":"reply","ActionBody":"No","Text":"No","TextSize":"regular","Columns":"3"}]}}`, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "viber:xy5/5y6O81+/kbWHpLhBoA==", Attachments: []string{"image/jpeg:https://localhost/image.jpg"}, - Status: "W", ResponseStatus: 200, - ResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - Headers: map[string]string{ + MsgText: "My pic!", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", MsgAttachments: []string{"image/jpeg:https://localhost/image.jpg"}, + ExpectedStatus: "W", MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"My pic!","type":"picture","tracking_data":"10","media":"{{ SERVER_URL }}/image.jpg"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"My pic!","type":"picture","tracking_data":"10","media":"{{ SERVER_URL }}/image.jpg"}`, + SendPrep: setSendURL}, {Label: "Long Description with Attachment", - Text: "Text description is longer that 10 characters", - URN: "viber:xy5/5y6O81+/kbWHpLhBoA==", Attachments: []string{"image/jpeg:https://localhost/image.jpg"}, - Status: "W", ResponseStatus: 200, - ResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - Headers: map[string]string{ + MsgText: "Text description is longer that 10 characters", + MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", MsgAttachments: []string{"image/jpeg:https://localhost/image.jpg"}, + ExpectedStatus: "W", MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Text description is longer that 10 characters","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Text description is longer that 10 characters","type":"text","tracking_data":"10"}`, + SendPrep: setSendURL}, {Label: "Send Attachment Video", - Text: "My video!", URN: "viber:xy5/5y6O81+/kbWHpLhBoA==", Attachments: []string{"video/mp4:https://localhost/video.mp4"}, - Status: "W", ResponseStatus: 200, - ResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - Headers: map[string]string{ + MsgText: "My video!", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", MsgAttachments: []string{"video/mp4:https://localhost/video.mp4"}, + ExpectedStatus: "W", MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"My video!","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"My video!","type":"text","tracking_data":"10"}`, + SendPrep: setSendURL}, {Label: "Send Attachment Audio", - Text: "My audio!", URN: "viber:xy5/5y6O81+/kbWHpLhBoA==", Attachments: []string{"audio/mp3:https://localhost/audio.mp3"}, - Status: "W", ResponseStatus: 200, - ResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - Headers: map[string]string{ + MsgText: "My audio!", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", MsgAttachments: []string{"audio/mp3:https://localhost/audio.mp3"}, + ExpectedStatus: "W", MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"My audio!","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"My audio!","type":"text","tracking_data":"10"}`, + SendPrep: setSendURL}, {Label: "Got non-0 response", - Text: "Simple Message", URN: "viber:xy5/5y6O81+/kbWHpLhBoA==", - Status: "E", ResponseStatus: 200, - ResponseBody: `{"status":3,"status_message":"InvalidToken"}`, - Headers: map[string]string{ + MsgText: "Simple Message", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + ExpectedStatus: "E", MockResponseStatus: 200, + MockResponseBody: `{"status":3,"status_message":"InvalidToken"}`, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, + SendPrep: setSendURL}, {Label: "Got Invalid JSON response", - Text: "Simple Message", URN: "viber:xy5/5y6O81+/kbWHpLhBoA==", - Status: "E", ResponseStatus: 200, - ResponseBody: `invalidJSON`, - Headers: map[string]string{ + MsgText: "Simple Message", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + ExpectedStatus: "E", MockResponseStatus: 200, + MockResponseBody: `invalidJSON`, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "viber:xy5/5y6O81+/kbWHpLhBoA==", - Status: "E", ResponseStatus: 401, - ResponseBody: `{"status":"5"}`, - Headers: map[string]string{ + MsgText: "Error Message", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + ExpectedStatus: "E", MockResponseStatus: 401, + MockResponseBody: `{"status":"5"}`, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Error Message","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Error Message","type":"text","tracking_data":"10"}`, + SendPrep: setSendURL}, } var invalidTokenSendTestCases = []ChannelSendTestCase{ - {Label: "Invalid token", Error: "missing auth token in config"}, + {Label: "Invalid token", ExpectedError: "missing auth token in config"}, } var buttonLayoutSendTestCases = []ChannelSendTestCase{ {Label: "Quick Reply With Layout With Column, Row and BgColor definitions", - Text: "Select a, b, c or d.", URN: "viber:xy5/5y6O81+/kbWHpLhBoA==", QuickReplies: []string{"a", "b", "c", "d"}, - Status: "W", ResponseStatus: 200, - ResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - Headers: map[string]string{ + MsgText: "Select a, b, c or d.", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", MsgQuickReplies: []string{"a", "b", "c", "d"}, + ExpectedStatus: "W", MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Select a, b, c or d.","type":"text","tracking_data":"10","keyboard":{"Type":"keyboard","DefaultHeight":false,"Buttons":[{"ActionType":"reply","ActionBody":"a","Text":"\u003cfont color=\"#ffffff\"\u003ea\u003c/font\u003e\u003cbr\u003e\u003cbr\u003e","TextSize":"large","Columns":"2","BgColor":"#f7bb3f"},{"ActionType":"reply","ActionBody":"b","Text":"\u003cfont color=\"#ffffff\"\u003eb\u003c/font\u003e\u003cbr\u003e\u003cbr\u003e","TextSize":"large","Columns":"2","BgColor":"#f7bb3f"},{"ActionType":"reply","ActionBody":"c","Text":"\u003cfont color=\"#ffffff\"\u003ec\u003c/font\u003e\u003cbr\u003e\u003cbr\u003e","TextSize":"large","Columns":"2","BgColor":"#f7bb3f"},{"ActionType":"reply","ActionBody":"d","Text":"\u003cfont color=\"#ffffff\"\u003ed\u003c/font\u003e\u003cbr\u003e\u003cbr\u003e","TextSize":"large","Columns":"6","BgColor":"#f7bb3f"}]}}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Select a, b, c or d.","type":"text","tracking_data":"10","keyboard":{"Type":"keyboard","DefaultHeight":false,"Buttons":[{"ActionType":"reply","ActionBody":"a","Text":"\u003cfont color=\"#ffffff\"\u003ea\u003c/font\u003e\u003cbr\u003e\u003cbr\u003e","TextSize":"large","Columns":"2","BgColor":"#f7bb3f"},{"ActionType":"reply","ActionBody":"b","Text":"\u003cfont color=\"#ffffff\"\u003eb\u003c/font\u003e\u003cbr\u003e\u003cbr\u003e","TextSize":"large","Columns":"2","BgColor":"#f7bb3f"},{"ActionType":"reply","ActionBody":"c","Text":"\u003cfont color=\"#ffffff\"\u003ec\u003c/font\u003e\u003cbr\u003e\u003cbr\u003e","TextSize":"large","Columns":"2","BgColor":"#f7bb3f"},{"ActionType":"reply","ActionBody":"d","Text":"\u003cfont color=\"#ffffff\"\u003ed\u003c/font\u003e\u003cbr\u003e\u003cbr\u003e","TextSize":"large","Columns":"6","BgColor":"#f7bb3f"}]}}`, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index 980755132..654eb7c82 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -385,13 +385,13 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var sendTestCases = []ChannelSendTestCase{ { - Label: "Send simple message", - Text: "Simple message", - URN: "vk:123456789", - Status: "S", - SendPrep: setSendURL, - ExternalID: "1", - Responses: map[MockedRequest]MockedResponse{ + Label: "Send simple message", + MsgText: "Simple message", + MsgURN: "vk:123456789", + ExpectedStatus: "S", + SendPrep: setSendURL, + ExpectedExternalID: "1", + MockResponses: map[MockedRequest]MockedResponse{ MockedRequest{ Method: "POST", Path: actionSendMessage, @@ -403,14 +403,14 @@ var sendTestCases = []ChannelSendTestCase{ }, }, { - Label: "Send photo attachment", - Text: "", - URN: "vk:123456789", - Attachments: []string{"image/png:https://foo.bar/image.png"}, - Status: "S", - SendPrep: setSendURL, - ExternalID: "1", - Responses: map[MockedRequest]MockedResponse{ + Label: "Send photo attachment", + MsgText: "", + MsgURN: "vk:123456789", + MsgAttachments: []string{"image/png:https://foo.bar/image.png"}, + ExpectedStatus: "S", + SendPrep: setSendURL, + ExpectedExternalID: "1", + MockResponses: map[MockedRequest]MockedResponse{ MockedRequest{ Method: "POST", Path: "/upload/photo", @@ -438,14 +438,14 @@ var sendTestCases = []ChannelSendTestCase{ }, }, { - Label: "Send photo and another attachment type", - Text: "Attachments", - URN: "vk:123456789", - Attachments: []string{"image/png:https://foo.bar/image.png", "audio/mp3:https://foo.bar/audio.mp3"}, - Status: "S", - SendPrep: setSendURL, - ExternalID: "1", - Responses: map[MockedRequest]MockedResponse{ + Label: "Send photo and another attachment type", + MsgText: "Attachments", + MsgURN: "vk:123456789", + MsgAttachments: []string{"image/png:https://foo.bar/image.png", "audio/mp3:https://foo.bar/audio.mp3"}, + ExpectedStatus: "S", + SendPrep: setSendURL, + ExpectedExternalID: "1", + MockResponses: map[MockedRequest]MockedResponse{ MockedRequest{ Method: "POST", Path: "/upload/photo", @@ -473,14 +473,14 @@ var sendTestCases = []ChannelSendTestCase{ }, }, { - Label: "Send keyboard", - Text: "Send keyboard", - URN: "vk:123456789", - QuickReplies: []string{"A", "B", "C", "D", "E"}, - Status: "S", - SendPrep: setSendURL, - ExternalID: "1", - Responses: map[MockedRequest]MockedResponse{ + Label: "Send keyboard", + MsgText: "Send keyboard", + MsgURN: "vk:123456789", + MsgQuickReplies: []string{"A", "B", "C", "D", "E"}, + ExpectedStatus: "S", + SendPrep: setSendURL, + ExpectedExternalID: "1", + MockResponses: map[MockedRequest]MockedResponse{ MockedRequest{ Method: "POST", Path: actionSendMessage, @@ -499,12 +499,12 @@ func mockAttachmentURLs(mediaServer *httptest.Server, testCases []ChannelSendTes for i, testCase := range testCases { mockedCase := testCase - for j, attachment := range testCase.Attachments { + for j, attachment := range testCase.MsgAttachments { prefix, _ := SplitAttachment(attachment) if mediaType := strings.Split(prefix, "/")[0]; mediaType != "image" { continue } - mockedCase.Attachments[j] = strings.Replace(attachment, "https://foo.bar", mediaServer.URL, 1) + mockedCase.MsgAttachments[j] = strings.Replace(attachment, "https://foo.bar", mediaServer.URL, 1) } casesWithMockedUrls[i] = mockedCase } diff --git a/handlers/wavy/wavy_test.go b/handlers/wavy/wavy_test.go index 123886238..f7fa44d08 100644 --- a/handlers/wavy/wavy_test.go +++ b/handlers/wavy/wavy_test.go @@ -108,23 +108,23 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ExternalID: "external1", - ResponseBody: `{"id": "external1"}`, - ResponseStatus: 200, - Headers: map[string]string{"username": "user1", "authenticationtoken": "token", "Accept": "application/json", "Content-Type": "application/json"}, - RequestBody: `{"destination":"250788383383","messageText":"Simple Message ☺\nhttps://foo.bar/image.jpg"}`, - SendPrep: setSendURL}, + MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + ExpectedExternalID: "external1", + MockResponseBody: `{"id": "external1"}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"username": "user1", "authenticationtoken": "token", "Accept": "application/json", "Content-Type": "application/json"}, + ExpectedRequestBody: `{"destination":"250788383383","messageText":"Simple Message ☺\nhttps://foo.bar/image.jpg"}`, + SendPrep: setSendURL}, {Label: "Error status 403", - Text: "Error Response", URN: "tel:+250788383383", - Status: "E", - RequestBody: `{"destination":"250788383383","messageText":"Error Response"}`, ResponseStatus: 403, + MsgText: "Error Response", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + ExpectedRequestBody: `{"destination":"250788383383","messageText":"Error Response"}`, MockResponseStatus: 403, SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: `Bad Gateway`, ResponseStatus: 501, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `Bad Gateway`, MockResponseStatus: 501, SendPrep: setSendURL}, } diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index bb27d9604..656efdd00 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -318,49 +318,49 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", - URN: "wechat:12345", - Status: "W", - ExternalID: "", - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message ☺", + MsgURN: "wechat:12345", + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"Simple Message ☺"}}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"Simple Message ☺"}}`, + SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "wechat:12345", - Status: "W", - ExternalID: "", - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "wechat:12345", + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"I need to keep adding more things to make it work"}}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"I need to keep adding more things to make it work"}}`, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", - URN: "wechat:12345", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ExternalID: "", - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "My pic!", + MsgURN: "wechat:12345", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, - RequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"My pic!\nhttps://foo.bar/image.jpg"}}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"My pic!\nhttps://foo.bar/image.jpg"}}`, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", - URN: "wechat:12345", - Status: "E", - ResponseStatus: 401, - Error: "received non 200 status: 401", - SendPrep: setSendURL}, + MsgText: "Error Message", + MsgURN: "wechat:12345", + ExpectedStatus: "E", + MockResponseStatus: 401, + ExpectedError: "received non 200 status: 401", + SendPrep: setSendURL}, } func setupBackend(mb *courier.MockBackend) { diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index f9bd81632..1a35a0229 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -370,506 +370,611 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Link Sending", - Text: "Link Sending https://link.com", URN: "whatsapp:250788123123", Path: "/v1/messages", - Status: "W", ExternalID: "157b5e14568e8", - ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"to":"250788123123","type":"text","preview_url":true,"text":{"body":"Link Sending https://link.com"}}`, - SendPrep: setSendURL}, - {Label: "Plain Send", - Text: "Simple Message", URN: "whatsapp:250788123123", Path: "/v1/messages", - Status: "W", ExternalID: "157b5e14568e8", - ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"to":"250788123123","type":"text","text":{"body":"Simple Message"}}`, - SendPrep: setSendURL}, - {Label: "Unicode Send", - Text: "☺", URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"to":"250788123123","type":"text","text":{"body":"☺"}}`, - SendPrep: setSendURL}, - {Label: "Error", - Text: "Error", URN: "whatsapp:250788123123", - Status: "E", - ResponseBody: `{ "errors": [{ "title": "Error Sending" }] }`, ResponseStatus: 403, - RequestBody: `{"to":"250788123123","type":"text","text":{"body":"Error"}}`, - SendPrep: setSendURL}, - {Label: "Rate Limit Engaged", - Text: "Error", URN: "whatsapp:250788123123", - Status: "E", - ResponseBody: `{ "errors": [{ "title": "Too many requests" }] }`, ResponseStatus: 429, - RequestBody: `{"to":"250788123123","type":"text","text":{"body":"Error"}}`, - SendPrep: setSendURL}, - {Label: "No Message ID", - Text: "Error", URN: "whatsapp:250788123123", - Status: "E", - ResponseBody: `{ "messages": [] }`, ResponseStatus: 200, - RequestBody: `{"to":"250788123123","type":"text","text":{"body":"Error"}}`, - SendPrep: setSendURL}, - {Label: "Error Field", - Text: "Error", URN: "whatsapp:250788123123", - Status: "E", - ResponseBody: `{ "errors": [{"title":"Error Sending"}] }`, ResponseStatus: 200, - RequestBody: `{"to":"250788123123","type":"text","text":{"body":"Error"}}`, - SendPrep: setSendURL}, - {Label: "Audio Send", - Text: "audio has no caption, sent as text", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"audio/mpeg:https://foo.bar/audio.mp3"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "Link Sending", + MsgText: "Link Sending https://link.com", + MsgURN: "whatsapp:250788123123", + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"to":"250788123123","type":"text","preview_url":true,"text":{"body":"Link Sending https://link.com"}}`, + ExpectedRequestPath: "/v1/messages", + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "whatsapp:250788123123", + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"to":"250788123123","type":"text","text":{"body":"Simple Message"}}`, + ExpectedRequestPath: "/v1/messages", + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "whatsapp:250788123123", + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"to":"250788123123","type":"text","text":{"body":"☺"}}`, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Error", + MsgText: "Error", + MsgURN: "whatsapp:250788123123", + MockResponseBody: `{ "errors": [{ "title": "Error Sending" }] }`, + MockResponseStatus: 403, + ExpectedRequestBody: `{"to":"250788123123","type":"text","text":{"body":"Error"}}`, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Rate Limit Engaged", + MsgText: "Error", + MsgURN: "whatsapp:250788123123", + MockResponseBody: `{ "errors": [{ "title": "Too many requests" }] }`, + MockResponseStatus: 429, + ExpectedRequestBody: `{"to":"250788123123","type":"text","text":{"body":"Error"}}`, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "No Message ID", + MsgText: "Error", + MsgURN: "whatsapp:250788123123", + MockResponseBody: `{ "messages": [] }`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"to":"250788123123","type":"text","text":{"body":"Error"}}`, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error Field", + MsgText: "Error", + MsgURN: "whatsapp:250788123123", + MockResponseBody: `{ "errors": [{"title":"Error Sending"}] }`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"to":"250788123123","type":"text","text":{"body":"Error"}}`, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Audio Send", + MsgText: "audio has no caption, sent as text", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"audio/mpeg:https://foo.bar/audio.mp3"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"audio","audio":{"link":"https://foo.bar/audio.mp3"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, - MockedRequest{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"text","text":{"body":"audio has no caption, sent as text"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - {Label: "Audio Send with link in text", - Text: "audio has no caption, sent as text with a https://example.com", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"audio/mpeg:https://foo.bar/audio.mp3"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "Audio Send with link in text", + MsgText: "audio has no caption, sent as text with a https://example.com", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"audio/mpeg:https://foo.bar/audio.mp3"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"audio","audio":{"link":"https://foo.bar/audio.mp3"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, - MockedRequest{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"text","preview_url":true,"text":{"body":"audio has no caption, sent as text with a https://example.com"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - {Label: "Document Send", - Text: "document caption", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"application/pdf:https://foo.bar/document.pdf"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "Document Send", + MsgText: "document caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"document","document":{"link":"https://foo.bar/document.pdf","caption":"document caption","filename":"document.pdf"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - {Label: "Image Send", - Text: "document caption", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "Image Send", + MsgText: "document caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg","caption":"document caption"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - {Label: "Video Send", - Text: "video caption", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"video/mp4:https://foo.bar/video.mp4"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "Video Send", + MsgText: "video caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"video","video":{"link":"https://foo.bar/video.mp4","caption":"video caption"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - {Label: "Template Send", - Text: "templated message", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Metadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "language": "eng", "variables": ["Chef", "tomorrow"]}}`), - ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 200, - RequestBody: `{"to":"250788123123","type":"template","template":{"namespace":"waba_namespace","name":"revive_issue","language":{"policy":"deterministic","code":"en"},"components":[{"type":"body","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, - SendPrep: setSendURL, + { + Label: "Template Send", + MsgText: "templated message", + MsgURN: "whatsapp:250788123123", + MsgMetadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "language": "eng", "variables": ["Chef", "tomorrow"]}}`), + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"to":"250788123123","type":"template","template":{"namespace":"waba_namespace","name":"revive_issue","language":{"policy":"deterministic","code":"en"},"components":[{"type":"body","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - {Label: "Template Country Language", - Text: "templated message", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Metadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "language": "eng", "country": "US", "variables": ["Chef", "tomorrow"]}}`), - ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 200, - RequestBody: `{"to":"250788123123","type":"template","template":{"namespace":"waba_namespace","name":"revive_issue","language":{"policy":"deterministic","code":"en_US"},"components":[{"type":"body","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, - SendPrep: setSendURL, + { + Label: "Template Country Language", + MsgText: "templated message", + MsgURN: "whatsapp:250788123123", + MsgMetadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "language": "eng", "country": "US", "variables": ["Chef", "tomorrow"]}}`), + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"to":"250788123123","type":"template","template":{"namespace":"waba_namespace","name":"revive_issue","language":{"policy":"deterministic","code":"en_US"},"components":[{"type":"body","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - {Label: "Template Namespace", - Text: "templated message", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Metadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "namespace": "wa_template_namespace", "language": "eng", "country": "US", "variables": ["Chef", "tomorrow"]}}`), - ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 200, - RequestBody: `{"to":"250788123123","type":"template","template":{"namespace":"wa_template_namespace","name":"revive_issue","language":{"policy":"deterministic","code":"en_US"},"components":[{"type":"body","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, - SendPrep: setSendURL, + { + Label: "Template Namespace", + MsgText: "templated message", + MsgURN: "whatsapp:250788123123", + MsgMetadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "namespace": "wa_template_namespace", "language": "eng", "country": "US", "variables": ["Chef", "tomorrow"]}}`), + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"to":"250788123123","type":"template","template":{"namespace":"wa_template_namespace","name":"revive_issue","language":{"policy":"deterministic","code":"en_US"},"components":[{"type":"body","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - {Label: "Template Invalid Language", - Text: "templated message", URN: "whatsapp:250788123123", - Error: `unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, - Metadata: json.RawMessage(`{"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}}`), + { + Label: "Template Invalid Language", + MsgText: "templated message", + MsgURN: "whatsapp:250788123123", + ExpectedError: `unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, + MsgMetadata: json.RawMessage(`{"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}}`), }, - {Label: "WhatsApp Contact Error", - Text: "contact status error", URN: "whatsapp:250788123123", - Status: "E", - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "WhatsApp Contact Error", + MsgText: "contact status error", + MsgURN: "whatsapp:250788123123", + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"text","text":{"body":"contact status error"}}`, - }: MockedResponse{ + }: { Status: 404, Body: `{"errors": [{"code":1006,"title":"Resource not found","details":"unknown contact"}]}`, }, - MockedRequest{ + { Method: "POST", Path: "/v1/contacts", Body: `{"blocking":"wait","contacts":["+250788123123"],"force_check":true}`, - }: MockedResponse{ + }: { Status: 200, Body: `{"contacts":[{"input":"+250788123123","status":"invalid"}]}`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "E", + SendPrep: setSendURL, }, - {Label: "Try Messaging Again After WhatsApp Contact Check", - Text: "try again", URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "Try Messaging Again After WhatsApp Contact Check", + MsgText: "try again", + MsgURN: "whatsapp:250788123123", + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"text","text":{"body":"try again"}}`, - }: MockedResponse{ + }: { Status: 404, Body: `{"errors": [{"code": 1006, "title": "Resource not found", "details": "unknown contact"}]}`, }, - MockedRequest{ + { Method: "POST", Path: "/v1/contacts", Body: `{"blocking":"wait","contacts":["+250788123123"],"force_check":true}`, - }: MockedResponse{ + }: { Status: 200, Body: `{"contacts": [{"input": "+250788123123", "status": "valid", "wa_id": "250788123123"}]}`, }, - MockedRequest{ + { Method: "POST", Path: "/v1/messages", RawQuery: "retry=1", Body: `{"to":"250788123123","type":"text","text":{"body":"try again"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{"messages": [{"id": "157b5e14568e8"}]}`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - {Label: "Try Messaging Again After WhatsApp Contact Check", - Text: "try again", URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "Try Messaging Again After WhatsApp Contact Check", + MsgText: "try again", + MsgURN: "whatsapp:250788123123", + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"text","text":{"body":"try again"}}`, - }: MockedResponse{ + }: { Status: 404, Body: `{"errors": [{"code": 1006, "title": "Resource not found", "details": "Could not retrieve phone number from contact store"}]}`, }, - MockedRequest{ + { Method: "POST", Path: "/v1/contacts", Body: `{"blocking":"wait","contacts":["+250788123123"],"force_check":true}`, - }: MockedResponse{ + }: { Status: 200, Body: `{"contacts": [{"input": "+250788123123", "status": "valid", "wa_id": "250788123123"}]}`, }, - MockedRequest{ + { Method: "POST", Path: "/v1/messages", RawQuery: "retry=1", Body: `{"to":"250788123123","type":"text","text":{"body":"try again"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{"messages": [{"id": "157b5e14568e8"}]}`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - {Label: "Try Messaging Again After WhatsApp Contact Check With Returned WhatsApp ID", - Text: "try again", URN: "whatsapp:5582999887766", - Status: "W", ExternalID: "157b5e14568e8", - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "Try Messaging Again After WhatsApp Contact Check With Returned WhatsApp ID", + MsgText: "try again", + MsgURN: "whatsapp:5582999887766", + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"5582999887766","type":"text","text":{"body":"try again"}}`, - }: MockedResponse{ + }: { Status: 404, Body: `{"errors": [{"code": 1006, "title": "Resource not found", "details": "unknown contact"}]}`, }, - MockedRequest{ + { Method: "POST", Path: "/v1/contacts", Body: `{"blocking":"wait","contacts":["+5582999887766"],"force_check":true}`, - }: MockedResponse{ + }: { Status: 200, Body: `{"contacts": [{"input": "+5582999887766", "status": "valid", "wa_id": "558299887766"}]}`, }, - MockedRequest{ + { Method: "POST", Path: "/v1/messages", RawQuery: "retry=1", Body: `{"to":"558299887766","type":"text","text":{"body":"try again"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{"messages": [{"id": "157b5e14568e8"}]}`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - {Label: "Interactive Button Message Send", - Text: "Interactive Button Msg", URN: "whatsapp:250788123123", QuickReplies: []string{"BUTTON1"}, - Status: "W", ExternalID: "157b5e14568e8", - ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, - SendPrep: setSendURL}, - {Label: "Interactive List Message Send", - Text: "Interactive List Msg", URN: "whatsapp:250788123123", QuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4"}, - Status: "W", ExternalID: "157b5e14568e8", - ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, - SendPrep: setSendURL}, - {Label: "Interactive Button Message Send with attachment", - Text: "Interactive Button Msg", URN: "whatsapp:250788123123", QuickReplies: []string{"BUTTON1"}, - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "Interactive Button Message Send", + MsgText: "Interactive Button Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"BUTTON1"}, + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL}, + { + Label: "Interactive List Message Send", + MsgText: "Interactive List Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4"}, + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL}, + { + Label: "Interactive Button Message Send with attachment", + MsgText: "Interactive Button Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"BUTTON1"}, + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, - MockedRequest{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL}, - {Label: "Interactive List Message Send with attachment", - Text: "Interactive List Msg", URN: "whatsapp:250788123123", QuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4"}, - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Interactive List Message Send with attachment", + MsgText: "Interactive List Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4"}, + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, - MockedRequest{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL}, - {Label: "Update URN with wa_id returned", - Text: "Simple Message", URN: "whatsapp:5511987654321", Path: "/v1/messages", - Status: "W", ExternalID: "157b5e14568e8", - ResponseBody: `{ "contacts":[{"input":"5511987654321","wa_id":"551187654321"}], "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 201, - RequestBody: `{"to":"5511987654321","type":"text","text":{"body":"Simple Message"}}`, - SendPrep: setSendURL, - NewURN: "whatsapp:551187654321"}, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Update URN with wa_id returned", + MsgText: "Simple Message", + MsgURN: "whatsapp:5511987654321", + MockResponseBody: `{ "contacts":[{"input":"5511987654321","wa_id":"551187654321"}], "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"to":"5511987654321","type":"text","text":{"body":"Simple Message"}}`, + ExpectedRequestPath: "/v1/messages", + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + ExpectedNewURN: "whatsapp:551187654321", + SendPrep: setSendURL, + }, } var mediaCacheSendTestCases = []ChannelSendTestCase{ - {Label: "Media Upload Error", - Text: "document caption", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"application/pdf:https://foo.bar/document.pdf"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "Media Upload Error", + MsgText: "document caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/media", Body: "media bytes", - }: MockedResponse{ + }: { Status: 401, Body: `{ "errors": [{"code":1005,"title":"Access denied","details":"Invalid credentials."}] }`, }, - MockedRequest{ + { Method: "POST", Path: "/v1/messages", BodyContains: `/document.pdf`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - {Label: "Previous Media Upload Error", - Text: "document caption", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"application/pdf:https://foo.bar/document.pdf"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "Previous Media Upload Error", + MsgText: "document caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/messages", BodyContains: `/document.pdf`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - {Label: "Media Upload OK", - Text: "video caption", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"video/mp4:https://foo.bar/video.mp4"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "Media Upload OK", + MsgText: "video caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/media", Body: "media bytes", - }: MockedResponse{ + }: { Status: 200, Body: `{ "media" : [{"id": "36c484d1-1283-4b94-988d-7276bdec4de2"}] }`, }, - MockedRequest{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"video","video":{"id":"36c484d1-1283-4b94-988d-7276bdec4de2","caption":"video caption"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - {Label: "Cached Media", - Text: "video caption", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"video/mp4:https://foo.bar/video.mp4"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "Cached Media", + MsgText: "video caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"video","video":{"id":"36c484d1-1283-4b94-988d-7276bdec4de2","caption":"video caption"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, { - Label: "Document Upload OK", - Text: "document caption", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"application/pdf:https://foo.bar/document2.pdf"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + Label: "Document Upload OK", + MsgText: "document caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"application/pdf:https://foo.bar/document2.pdf"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/media", Body: "media bytes", - }: MockedResponse{ + }: { Status: 200, Body: `{ "media" : [{"id": "25c484d1-1283-4b94-988d-7276bdec4ef3"}] }`, }, - MockedRequest{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"document","document":{"id":"25c484d1-1283-4b94-988d-7276bdec4ef3","caption":"document caption","filename":"document2.pdf"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, - {Label: "Cached Document", - Text: "document caption", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Attachments: []string{"application/pdf:https://foo.bar/document2.pdf"}, - Responses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { + Label: "Cached Document", + MsgText: "document caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"application/pdf:https://foo.bar/document2.pdf"}, + MockResponses: map[MockedRequest]MockedResponse{ + { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"document","document":{"id":"25c484d1-1283-4b94-988d-7276bdec4ef3","caption":"document caption","filename":"document2.pdf"}}`, - }: MockedResponse{ + }: { Status: 201, Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, } var hsmSupportSendTestCases = []ChannelSendTestCase{ - {Label: "Template Send", - Text: "templated message", - URN: "whatsapp:250788123123", - Status: "W", ExternalID: "157b5e14568e8", - Metadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "language": "eng", "variables": ["Chef", "tomorrow"]}}`), - ResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, ResponseStatus: 200, - RequestBody: `{"to":"250788123123","type":"hsm","hsm":{"namespace":"waba_namespace","element_name":"revive_issue","language":{"policy":"deterministic","code":"en"},"localizable_params":[{"default":"Chef"},{"default":"tomorrow"}]}}`, - SendPrep: setSendURL, + { + Label: "Template Send", + MsgText: "templated message", + MsgURN: "whatsapp:250788123123", + MsgMetadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "language": "eng", "variables": ["Chef", "tomorrow"]}}`), + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"to":"250788123123","type":"hsm","hsm":{"namespace":"waba_namespace","element_name":"revive_issue","language":{"policy":"deterministic","code":"en"},"localizable_params":[{"default":"Chef"},{"default":"tomorrow"}]}}`, + ExpectedStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, } @@ -879,8 +984,8 @@ func mockAttachmentURLs(mediaServer *httptest.Server, testCases []ChannelSendTes for i, testCase := range testCases { mockedCase := testCase - for j, attachment := range testCase.Attachments { - mockedCase.Attachments[j] = strings.Replace(attachment, "https://foo.bar", mediaServer.URL, 1) + for j, attachment := range testCase.MsgAttachments { + mockedCase.MsgAttachments[j] = strings.Replace(attachment, "https://foo.bar", mediaServer.URL, 1) } casesWithMockedUrls[i] = mockedCase } diff --git a/handlers/yo/yo_test.go b/handlers/yo/yo_test.go index 7ec98559b..693d8e607 100644 --- a/handlers/yo/yo_test.go +++ b/handlers/yo/yo_test.go @@ -54,10 +54,10 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var getSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "ybs_autocreate_status=OK", ResponseStatus: 200, - URLParams: map[string]string{ + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "ybs_autocreate_status=OK", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{ "sms_content": "Simple Message", "destinations": "250788383383", "ybsacctno": "yo-username", @@ -65,36 +65,36 @@ var getSendTestCases = []ChannelSendTestCase{ "origin": "2020"}, SendPrep: setSendURL}, {Label: "Blacklisted", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "F", - ResponseBody: "ybs_autocreate_status=ERROR&ybs_autocreate_message=256794224665%3ABLACKLISTED", ResponseStatus: 200, - URLParams: map[string]string{"sms_content": "Simple Message", "destinations": string("250788383383"), "origin": "2020"}, - SendPrep: setSendURL, - Stopped: true}, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "F", + MockResponseBody: "ybs_autocreate_status=ERROR&ybs_autocreate_message=256794224665%3ABLACKLISTED", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"sms_content": "Simple Message", "destinations": string("250788383383"), "origin": "2020"}, + SendPrep: setSendURL, + ExpectedStopEvent: true}, {Label: "Errored wrong authorization", - Text: "Simple Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: "ybs_autocreate_status=ERROR&ybs_autocreate_message=YBS+AutoCreate+Subsystem%3A+Access+denied+due+to+wrong+authorization+code", ResponseStatus: 200, - URLParams: map[string]string{"sms_content": "Simple Message", "destinations": string("250788383383"), "origin": "2020"}, - SendPrep: setSendURL}, + MsgText: "Simple Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: "ybs_autocreate_status=ERROR&ybs_autocreate_message=YBS+AutoCreate+Subsystem%3A+Access+denied+due+to+wrong+authorization+code", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"sms_content": "Simple Message", "destinations": string("250788383383"), "origin": "2020"}, + SendPrep: setSendURL}, {Label: "Unicode Send", - Text: "☺", URN: "tel:+250788383383", - Status: "W", - ResponseBody: "ybs_autocreate_status=OK", ResponseStatus: 200, - URLParams: map[string]string{"sms_content": "☺", "destinations": string("250788383383"), "origin": "2020"}, - SendPrep: setSendURL}, + MsgText: "☺", MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "ybs_autocreate_status=OK", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"sms_content": "☺", "destinations": string("250788383383"), "origin": "2020"}, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", URN: "tel:+250788383383", - Status: "E", - ResponseBody: "Error", ResponseStatus: 401, - URLParams: map[string]string{"sms_content": `Error Message`, "destinations": string("250788383383")}, - SendPrep: setSendURL}, + MsgText: "Error Message", MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: "Error", MockResponseStatus: 401, + ExpectedURLParams: map[string]string{"sms_content": `Error Message`, "destinations": string("250788383383")}, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", URN: "tel:+250788383383", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ResponseBody: "ybs_autocreate_status=OK", ResponseStatus: 200, - URLParams: map[string]string{"sms_content": "My pic!\nhttps://foo.bar/image.jpg", "destinations": string("250788383383"), "origin": "2020"}, - SendPrep: setSendURL}, + MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + MockResponseBody: "ybs_autocreate_status=OK", MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"sms_content": "My pic!\nhttps://foo.bar/image.jpg", "destinations": string("250788383383"), "origin": "2020"}, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/zenvia/zenvia_test.go b/handlers/zenvia/zenvia_test.go index f373976e0..2ef9db8b4 100644 --- a/handlers/zenvia/zenvia_test.go +++ b/handlers/zenvia/zenvia_test.go @@ -254,136 +254,136 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultWhatsappSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", - URN: "tel:+250788383383", - Status: "W", - ExternalID: "55555", - ResponseBody: `{"id": "55555"}`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "55555", + MockResponseBody: `{"id": "55555"}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "X-API-TOKEN": "zv-api-token", }, - RequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"Simple Message ☺"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"Simple Message ☺"}]}`, + SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+250788383383", - Status: "W", - ExternalID: "55555", - ResponseBody: `{"id": "55555"}`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "55555", + MockResponseBody: `{"id": "55555"}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "X-API-TOKEN": "zv-api-token", }, - RequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say,"},{"type":"text","text":"I need to keep adding more things to make it work"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say,"},{"type":"text","text":"I need to keep adding more things to make it work"}]}`, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", - URN: "tel:+250788383383", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ExternalID: "55555", - ResponseBody: `{"id": "55555"}`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + ExpectedExternalID: "55555", + MockResponseBody: `{"id": "55555"}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "X-API-TOKEN": "zv-api-token", }, - RequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"file","fileUrl":"https://foo.bar/image.jpg","fileMimeType":"image/jpeg"},{"type":"text","text":"My pic!"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"file","fileUrl":"https://foo.bar/image.jpg","fileMimeType":"image/jpeg"},{"type":"text","text":"My pic!"}]}`, + SendPrep: setSendURL}, {Label: "No External ID", - Text: "No External ID", - URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{"code": "400","message": "Validation error","details": [{"code": "400","path": "Error","message": "Error description"}]}`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "No External ID", + MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{"code": "400","message": "Validation error","details": [{"code": "400","path": "Error","message": "Error description"}]}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "X-API-TOKEN": "zv-api-token", }, - RequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"No External ID"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"No External ID"}]}`, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", - URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "failed" }`, - ResponseStatus: 401, - RequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"Error Message"}]}`, - SendPrep: setSendURL}, + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{ "error": "failed" }`, + MockResponseStatus: 401, + ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"Error Message"}]}`, + SendPrep: setSendURL}, } var defaultSMSSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", - URN: "tel:+250788383383", - Status: "W", - ExternalID: "55555", - ResponseBody: `{"id": "55555"}`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "55555", + MockResponseBody: `{"id": "55555"}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "X-API-TOKEN": "zv-api-token", }, - RequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"Simple Message ☺"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"Simple Message ☺"}]}`, + SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+250788383383", - Status: "W", - ExternalID: "55555", - ResponseBody: `{"id": "55555"}`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "55555", + MockResponseBody: `{"id": "55555"}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "X-API-TOKEN": "zv-api-token", }, - RequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say,"},{"type":"text","text":"I need to keep adding more things to make it work"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say,"},{"type":"text","text":"I need to keep adding more things to make it work"}]}`, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", - URN: "tel:+250788383383", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ExternalID: "55555", - ResponseBody: `{"id": "55555"}`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + ExpectedExternalID: "55555", + MockResponseBody: `{"id": "55555"}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "X-API-TOKEN": "zv-api-token", }, - RequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"My pic!\nhttps://foo.bar/image.jpg"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"My pic!\nhttps://foo.bar/image.jpg"}]}`, + SendPrep: setSendURL}, {Label: "No External ID", - Text: "No External ID", - URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{"code": "400","message": "Validation error","details": [{"code": "400","path": "Error","message": "Error description"}]}`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "No External ID", + MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{"code": "400","message": "Validation error","details": [{"code": "400","path": "Error","message": "Error description"}]}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "X-API-TOKEN": "zv-api-token", }, - RequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"No External ID"}]}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"No External ID"}]}`, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", - URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "failed" }`, - ResponseStatus: 401, - RequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"Error Message"}]}`, - SendPrep: setSendURL}, + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{ "error": "failed" }`, + MockResponseStatus: 401, + ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"Error Message"}]}`, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/zenviaold/zenviaold_test.go b/handlers/zenviaold/zenviaold_test.go index a8b7048bf..b7886d682 100644 --- a/handlers/zenviaold/zenviaold_test.go +++ b/handlers/zenviaold/zenviaold_test.go @@ -136,69 +136,69 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - Text: "Simple Message ☺", - URN: "tel:+250788383383", - Status: "W", - ExternalID: "", - ResponseBody: `{"sendSmsResponse":{"statusCode":"00","statusDescription":"Ok","detailCode":"000","detailDescription":"Message Sent"}}`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseBody: `{"sendSmsResponse":{"statusCode":"00","statusDescription":"Ok","detailCode":"000","detailDescription":"Message Sent"}}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", }, - RequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"Simple Message ☺","callbackOption":"FINAL","id":"10","aggregateId":""}}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"Simple Message ☺","callbackOption":"FINAL","id":"10","aggregateId":""}}`, + SendPrep: setSendURL}, {Label: "Long Send", - Text: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - URN: "tel:+250788383383", - Status: "W", - ExternalID: "", - ResponseBody: `{"sendSmsResponse":{"statusCode":"00","statusDescription":"Ok","detailCode":"000","detailDescription":"Message Sent"}}`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseBody: `{"sendSmsResponse":{"statusCode":"00","statusDescription":"Ok","detailCode":"000","detailDescription":"Message Sent"}}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", }, - RequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"I need to keep adding more things to make it work","callbackOption":"FINAL","id":"10","aggregateId":""}}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"I need to keep adding more things to make it work","callbackOption":"FINAL","id":"10","aggregateId":""}}`, + SendPrep: setSendURL}, {Label: "Send Attachment", - Text: "My pic!", - URN: "tel:+250788383383", - Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", - ExternalID: "", - ResponseBody: `{"sendSmsResponse":{"statusCode":"00","statusDescription":"Ok","detailCode":"000","detailDescription":"Message Sent"}}`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + ExpectedExternalID: "", + MockResponseBody: `{"sendSmsResponse":{"statusCode":"00","statusDescription":"Ok","detailCode":"000","detailDescription":"Message Sent"}}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", }, - RequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"My pic!\nhttps://foo.bar/image.jpg","callbackOption":"FINAL","id":"10","aggregateId":""}}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"My pic!\nhttps://foo.bar/image.jpg","callbackOption":"FINAL","id":"10","aggregateId":""}}`, + SendPrep: setSendURL}, {Label: "No External ID", - Text: "No External ID", - URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{"sendSmsResponse" :{"statusCode" :"05","statusDescription" :"Blocked","detailCode":"140","detailDescription":"Mobile number not covered"}}`, - ResponseStatus: 200, - Headers: map[string]string{ + MsgText: "No External ID", + MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{"sendSmsResponse" :{"statusCode" :"05","statusDescription" :"Blocked","detailCode":"140","detailDescription":"Mobile number not covered"}}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", }, - RequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"No External ID","callbackOption":"FINAL","id":"10","aggregateId":""}}`, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"No External ID","callbackOption":"FINAL","id":"10","aggregateId":""}}`, + SendPrep: setSendURL}, {Label: "Error Sending", - Text: "Error Message", - URN: "tel:+250788383383", - Status: "E", - ResponseBody: `{ "error": "failed" }`, - ResponseStatus: 401, - RequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"Error Message","callbackOption":"FINAL","id":"10","aggregateId":""}}`, - SendPrep: setSendURL}, + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + ExpectedStatus: "E", + MockResponseBody: `{ "error": "failed" }`, + MockResponseStatus: 401, + ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"Error Message","callbackOption":"FINAL","id":"10","aggregateId":""}}`, + SendPrep: setSendURL}, } func TestSending(t *testing.T) { From 4f36a6b3c3d869150482dcf7b1ac95e62bbb69d2 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 10 Aug 2022 12:27:10 -0500 Subject: [PATCH 056/294] Convert more channels to use logger --- handlers/rocketchat/rocketchat.go | 12 ++++-------- handlers/start/start.go | 10 +++------- handlers/telesom/telesom.go | 11 ++++------- 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/handlers/rocketchat/rocketchat.go b/handlers/rocketchat/rocketchat.go index ff1cbb6d9..cf9847935 100644 --- a/handlers/rocketchat/rocketchat.go +++ b/handlers/rocketchat/rocketchat.go @@ -139,16 +139,12 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Token %s", secret)) - trace, err := handlers.MakeHTTPRequest(req) - - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - - if err != nil { - return status, err + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return status, nil } - msgID, err := jsonparser.GetString(trace.ResponseBody, "id") + msgID, err := jsonparser.GetString(respBody, "id") if err == nil { status.SetExternalID(msgID) } diff --git a/handlers/start/start.go b/handlers/start/start.go index af2e4865f..bb63b88e1 100644 --- a/handlers/start/start.go +++ b/handlers/start/start.go @@ -163,17 +163,13 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/xml; charset=utf8") req.SetBasicAuth(username, password) - trace, err := handlers.MakeHTTPRequest(req) - - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace) - status.AddLog(log) - if err != nil { - log.WithError("Message Send Error", err) + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } response := &mtResponse{} - err = xml.Unmarshal(trace.ResponseBody, response) + err = xml.Unmarshal(respBody, response) if err == nil { status.SetStatus(courier.MsgWired) if i == 0 { diff --git a/handlers/telesom/telesom.go b/handlers/telesom/telesom.go index 33e44ceb2..ca42e49d0 100644 --- a/handlers/telesom/telesom.go +++ b/handlers/telesom/telesom.go @@ -114,18 +114,15 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - trace, err := handlers.MakeInsecureHTTPRequest(req) - - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - if strings.Contains(string(trace.ResponseBody), "Success") { + if strings.Contains(string(respBody), "Success") { status.SetStatus(courier.MsgWired) } else { - log.WithError("Message Send Error", fmt.Errorf("Received invalid response content: %s", string(trace.ResponseBody))) + logger.Error(fmt.Errorf("Received invalid response content: %s", string(respBody))) } } return status, nil From 6005913aca4e2386191c2c367655e7fb3b65c341 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 10 Aug 2022 13:13:59 -0500 Subject: [PATCH 057/294] Move testing code out of courier package and into new test package --- channel_log.go | 8 +- channel_log_test.go | 3 +- handler_test.go | 86 +- .../africastalking/africastalking_test.go | 7 +- handlers/arabiacell/arabiacell_test.go | 5 +- handlers/base_test.go | 5 +- handlers/blackmyna/blackmyna_test.go | 5 +- handlers/bongolive/bongolive_test.go | 5 +- handlers/burstsms/burstsms_test.go | 5 +- handlers/chikka/chikka_test.go | 5 +- handlers/clickatell/clickatell_test.go | 5 +- handlers/clickmobile/clickmobile_test.go | 7 +- handlers/clicksend/clicksend_test.go | 5 +- handlers/dart/dart_test.go | 5 +- handlers/discord/discord_test.go | 5 +- handlers/dmark/dmark_test.go | 5 +- handlers/external/external_test.go | 39 +- handlers/facebook/facebook_test.go | 6 +- handlers/facebookapp/facebookapp_test.go | 117 +-- handlers/firebase/firebase_test.go | 5 +- handlers/freshchat/freshchat_test.go | 5 +- handlers/globe/globe_test.go | 5 +- .../highconnection/highconnection_test.go | 5 +- handlers/hormuud/hormuud_test.go | 5 +- handlers/http_test.go | 5 +- handlers/i2sms/i2sms_test.go | 5 +- handlers/infobip/infobip_test.go | 7 +- handlers/jasmin/jasmin_test.go | 7 +- handlers/jiochat/jiochat_test.go | 11 +- handlers/junebug/junebug_test.go | 7 +- handlers/kaleyra/kaleyra_test.go | 3 +- handlers/kannel/kannel_test.go | 13 +- handlers/line/line_test.go | 7 +- handlers/m3tech/m3tech_test.go | 5 +- handlers/macrokiosk/macrokiosk_test.go | 5 +- handlers/mblox/mblox_test.go | 5 +- handlers/media_test.go | 15 +- handlers/messangi/messangi_test.go | 5 +- handlers/mtarget/mtarget_test.go | 5 +- handlers/nexmo/nexmo_test.go | 5 +- handlers/novo/novo_test.go | 5 +- handlers/playmobile/playmobile_test.go | 5 +- handlers/plivo/plivo_test.go | 5 +- handlers/redrabbit/redrabbit_test.go | 3 +- handlers/rocketchat/rocketchat_test.go | 5 +- handlers/shaqodoon/shaqodoon_test.go | 7 +- handlers/slack/slack_test.go | 3 +- handlers/smscentral/smscentral_test.go | 5 +- handlers/start/start_test.go | 5 +- handlers/telegram/telegram_test.go | 5 +- handlers/telesom/telesom_test.go | 7 +- handlers/test.go | 9 +- handlers/thinq/thinq_test.go | 5 +- handlers/twiml/twiml_test.go | 27 +- handlers/twitter/twitter_test.go | 3 +- handlers/viber/viber_test.go | 11 +- handlers/vk/vk_test.go | 3 +- handlers/wavy/wavy_test.go | 5 +- handlers/wechat/wechat_test.go | 11 +- handlers/whatsapp/whatsapp_test.go | 19 +- handlers/yo/yo_test.go | 5 +- handlers/zenvia/zenvia_test.go | 11 +- handlers/zenviaold/zenviaold_test.go | 6 +- server_test.go | 10 +- test.go | 791 ------------------ test/backend.go | 396 +++++++++ test/channel.go | 170 ++++ test/channel_event.go | 46 + test/contact.go | 15 + test/media.go | 36 + test/msg.go | 96 +++ test/status.go | 48 ++ test/utils.go | 11 + 73 files changed, 1166 insertions(+), 1086 deletions(-) delete mode 100644 test.go create mode 100644 test/backend.go create mode 100644 test/channel.go create mode 100644 test/channel_event.go create mode 100644 test/contact.go create mode 100644 test/media.go create mode 100644 test/msg.go create mode 100644 test/status.go create mode 100644 test/utils.go diff --git a/channel_log.go b/channel_log.go index 7ccf345c2..274ca25d3 100644 --- a/channel_log.go +++ b/channel_log.go @@ -25,14 +25,14 @@ func NewChannelLog(description string, channel Channel, msgID MsgID, method stri URL: url, StatusCode: statusCode, Error: errString, - Request: sanitizeBody(request), - Response: sanitizeBody(response), + Request: SanitizeBody(request), + Response: SanitizeBody(response), CreatedOn: time.Now(), Elapsed: elapsed, } } -func sanitizeBody(body string) string { +func SanitizeBody(body string) string { parts := strings.SplitN(body, "\r\n\r\n", 2) if len(parts) < 2 { return body @@ -56,7 +56,7 @@ func NewChannelLogFromTrace(description string, channel Channel, msgID MsgID, tr MsgID: msgID, Method: trace.Request.Method, URL: trace.Request.URL.String(), - Request: sanitizeBody(string(trace.RequestTrace)), + Request: SanitizeBody(string(trace.RequestTrace)), CreatedOn: trace.StartTime, Elapsed: trace.EndTime.Sub(trace.StartTime), } diff --git a/channel_log_test.go b/channel_log_test.go index 1c85631d4..01420271d 100644 --- a/channel_log_test.go +++ b/channel_log_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/nyaruka/courier" + "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/httpx" "github.com/stretchr/testify/assert" ) @@ -18,7 +19,7 @@ func TestNewChannelLogFromTrace(t *testing.T) { })) defer httpx.SetRequestor(httpx.DefaultRequestor) - channel := courier.NewMockChannel("fef91e9b-a6ed-44fb-b6ce-feed8af585a8", "NX", "1234", "US", nil) + channel := test.NewMockChannel("fef91e9b-a6ed-44fb-b6ce-feed8af585a8", "NX", "1234", "US", nil) // make a request that will have a response req, _ := http.NewRequest("POST", "https://api.messages.com/send.json", nil) diff --git a/handler_test.go b/handler_test.go index bcd9a96ba..43cd454c9 100644 --- a/handler_test.go +++ b/handler_test.go @@ -1,4 +1,4 @@ -package courier +package courier_test import ( "context" @@ -8,35 +8,37 @@ import ( "testing" "time" + "github.com/nyaruka/courier" + "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/urns" "github.com/stretchr/testify/assert" ) func init() { - RegisterHandler(NewHandler()) + courier.RegisterHandler(NewHandler()) } type dummyHandler struct { - server Server - backend Backend + server courier.Server + backend courier.Backend } // NewHandler returns a new Dummy handler -func NewHandler() ChannelHandler { +func NewHandler() courier.ChannelHandler { return &dummyHandler{} } -func (h *dummyHandler) ChannelName() string { return "Dummy Handler" } -func (h *dummyHandler) ChannelType() ChannelType { return ChannelType("DM") } -func (h *dummyHandler) UseChannelRouteUUID() bool { return true } +func (h *dummyHandler) ChannelName() string { return "Dummy Handler" } +func (h *dummyHandler) ChannelType() courier.ChannelType { return courier.ChannelType("DM") } +func (h *dummyHandler) UseChannelRouteUUID() bool { return true } -func (h *dummyHandler) GetChannel(ctx context.Context, r *http.Request) (Channel, error) { - dmChannel := NewMockChannel("e4bb1578-29da-4fa5-a214-9da19dd24230", "DM", "2020", "US", map[string]interface{}{}) +func (h *dummyHandler) GetChannel(ctx context.Context, r *http.Request) (courier.Channel, error) { + dmChannel := test.NewMockChannel("e4bb1578-29da-4fa5-a214-9da19dd24230", "DM", "2020", "US", map[string]interface{}{}) return dmChannel, nil } // Initialize is called by the engine once everything is loaded -func (h *dummyHandler) Initialize(s Server) error { +func (h *dummyHandler) Initialize(s courier.Server) error { h.server = s h.backend = s.Backend() s.AddHandlerRoute(h, http.MethodGet, "receive", h.receiveMsg) @@ -44,12 +46,12 @@ func (h *dummyHandler) Initialize(s Server) error { } // Send sends the given message, logging any HTTP calls or errors -func (h *dummyHandler) Send(ctx context.Context, msg Msg, logger *ChannelLogger) (MsgStatus, error) { - return h.backend.NewMsgStatusForID(msg.Channel(), msg.ID(), MsgSent), nil +func (h *dummyHandler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { + return h.backend.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgSent), nil } // ReceiveMsg sends the passed in message, returning any error -func (h *dummyHandler) receiveMsg(ctx context.Context, channel Channel, w http.ResponseWriter, r *http.Request) ([]Event, error) { +func (h *dummyHandler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { r.ParseForm() from := r.Form.Get("from") text := r.Form.Get("text") @@ -61,11 +63,11 @@ func (h *dummyHandler) receiveMsg(ctx context.Context, channel Channel, w http.R w.WriteHeader(200) w.Write([]byte("ok")) h.backend.WriteMsg(ctx, msg) - return []Event{msg}, nil + return []courier.Event{msg}, nil } -func testConfig() *Config { - config := NewConfig() +func testConfig() *courier.Config { + config := courier.NewConfig() config.DB = "postgres://courier:courier@localhost:5432/courier_test?sslmode=disable" config.Redis = "redis://localhost:6379/0" return config @@ -75,8 +77,8 @@ func TestHandling(t *testing.T) { assert := assert.New(t) // create our backend and server - mb := NewMockBackend() - s := NewServer(testConfig(), mb) + mb := test.NewMockBackend() + s := courier.NewServer(testConfig(), mb) // start everything s.Start() @@ -85,60 +87,46 @@ func TestHandling(t *testing.T) { time.Sleep(100 * time.Millisecond) // create and add a new outgoing message - xxChannel := NewMockChannel("53e5aafa-8155-449d-9009-fcb30d54bd26", "XX", "2020", "US", map[string]interface{}{}) - dmChannel := NewMockChannel("e4bb1578-29da-4fa5-a214-9da19dd24230", "DM", "2020", "US", map[string]interface{}{}) + xxChannel := test.NewMockChannel("53e5aafa-8155-449d-9009-fcb30d54bd26", "XX", "2020", "US", map[string]interface{}{}) + dmChannel := test.NewMockChannel("e4bb1578-29da-4fa5-a214-9da19dd24230", "DM", "2020", "US", map[string]interface{}{}) mb.AddChannel(dmChannel) - msg := &mockMsg{ - channel: xxChannel, - id: NewMsgID(101), - uuid: NilMsgUUID, - text: "test message", - urn: "tel:+250788383383", - } + msg := test.NewMockMsg(courier.NewMsgID(101), courier.NilMsgUUID, xxChannel, "tel:+250788383383", "test message") mb.PushOutgoingMsg(msg) // sleep a second, sender should take care of it in that time time.Sleep(time.Second) // message should have errored because we don't have a registered handler - assert.Equal(1, len(mb.msgStatuses)) - assert.Equal(msg.ID(), mb.msgStatuses[0].ID()) - assert.Equal(MsgErrored, mb.msgStatuses[0].Status()) - assert.Equal(1, len(mb.channelLogs)) + assert.Equal(1, len(mb.MsgStatuses())) + assert.Equal(msg.ID(), mb.MsgStatuses()[0].ID()) + assert.Equal(courier.MsgErrored, mb.MsgStatuses()[0].Status()) + assert.Equal(1, len(mb.ChannelLogs())) - // clear our statuses - mb.msgStatuses = nil + mb.ClearMsgStatuses() // change our channel to our dummy channel - msg = &mockMsg{ - channel: dmChannel, - id: NewMsgID(102), - uuid: NilMsgUUID, - text: "test message 2", - urn: "tel:+250788383383", - } + msg = test.NewMockMsg(courier.NewMsgID(102), courier.NilMsgUUID, dmChannel, "tel:+250788383383", "test message 2") // send it mb.PushOutgoingMsg(msg) time.Sleep(time.Second) // message should be marked as wired - assert.Equal(1, len(mb.msgStatuses)) - assert.Equal(msg.ID(), mb.msgStatuses[0].ID()) - assert.Equal(MsgSent, mb.msgStatuses[0].Status()) + assert.Equal(1, len(mb.MsgStatuses())) + assert.Equal(msg.ID(), mb.MsgStatuses()[0].ID()) + assert.Equal(courier.MsgSent, mb.MsgStatuses()[0].Status()) - // clear our statuses - mb.msgStatuses = nil + mb.ClearMsgStatuses() // send the message again, should be skipped but again marked as wired mb.PushOutgoingMsg(msg) time.Sleep(time.Second) // message should be marked as wired - assert.Equal(1, len(mb.msgStatuses)) - assert.Equal(msg.ID(), mb.msgStatuses[0].ID()) - assert.Equal(MsgWired, mb.msgStatuses[0].Status()) + assert.Equal(1, len(mb.MsgStatuses())) + assert.Equal(msg.ID(), mb.MsgStatuses()[0].ID()) + assert.Equal(courier.MsgWired, mb.MsgStatuses()[0].Status()) // try to receive a message instead resp, err := http.Get("http://localhost:8080/c/dm/e4bb1578-29da-4fa5-a214-9da19dd24230/receive") diff --git a/handlers/africastalking/africastalking_test.go b/handlers/africastalking/africastalking_test.go index 2ff815581..1f9537fbe 100644 --- a/handlers/africastalking/africastalking_test.go +++ b/handlers/africastalking/africastalking_test.go @@ -7,10 +7,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AT", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AT", "2020", "US", nil), } var ( @@ -123,12 +124,12 @@ var sharedSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AT", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AT", "2020", "US", map[string]interface{}{ courier.ConfigUsername: "Username", courier.ConfigAPIKey: "KEY", }) - var sharedChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AT", "2020", "US", + var sharedChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AT", "2020", "US", map[string]interface{}{ courier.ConfigUsername: "Username", courier.ConfigAPIKey: "KEY", diff --git a/handlers/arabiacell/arabiacell_test.go b/handlers/arabiacell/arabiacell_test.go index aed990867..8c490c878 100644 --- a/handlers/arabiacell/arabiacell_test.go +++ b/handlers/arabiacell/arabiacell_test.go @@ -6,10 +6,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AC", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AC", "2020", "US", nil), } var ( @@ -92,7 +93,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AC", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AC", "2020", "US", map[string]interface{}{ courier.ConfigUsername: "user1", courier.ConfigPassword: "pass1", diff --git a/handlers/base_test.go b/handlers/base_test.go index de0b9bac0..6ab242775 100644 --- a/handlers/base_test.go +++ b/handlers/base_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/nyaruka/courier" + "github.com/nyaruka/courier/test" "github.com/stretchr/testify/assert" ) @@ -47,13 +48,13 @@ func TestSplitMsg(t *testing.T) { func TestSplitMsgByChannel(t *testing.T) { assert := assert.New(t) - var channelWithMaxLength = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AC", "2020", "US", + var channelWithMaxLength = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AC", "2020", "US", map[string]interface{}{ courier.ConfigUsername: "user1", courier.ConfigPassword: "pass1", courier.ConfigMaxLength: 25, }) - var channelWithoutMaxLength = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AC", "2020", "US", + var channelWithoutMaxLength = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AC", "2020", "US", map[string]interface{}{ courier.ConfigUsername: "user1", courier.ConfigPassword: "pass1", diff --git a/handlers/blackmyna/blackmyna_test.go b/handlers/blackmyna/blackmyna_test.go index dc3eb4d76..65681ca39 100644 --- a/handlers/blackmyna/blackmyna_test.go +++ b/handlers/blackmyna/blackmyna_test.go @@ -6,10 +6,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "BM", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "BM", "2020", "US", nil), } var ( @@ -111,7 +112,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "BM", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "BM", "2020", "US", map[string]interface{}{ courier.ConfigPassword: "Password", courier.ConfigUsername: "Username", diff --git a/handlers/bongolive/bongolive_test.go b/handlers/bongolive/bongolive_test.go index f68a79407..0863c86b4 100644 --- a/handlers/bongolive/bongolive_test.go +++ b/handlers/bongolive/bongolive_test.go @@ -6,10 +6,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "BL", "2020", "KE", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "BL", "2020", "KE", nil), } var ( @@ -108,7 +109,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "BL", "2020", "KE", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "BL", "2020", "KE", map[string]interface{}{ courier.ConfigUsername: "user1", courier.ConfigPassword: "pass1", diff --git a/handlers/burstsms/burstsms_test.go b/handlers/burstsms/burstsms_test.go index c6b501956..a9a67b21e 100644 --- a/handlers/burstsms/burstsms_test.go +++ b/handlers/burstsms/burstsms_test.go @@ -6,10 +6,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "BS", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "BS", "2020", "US", nil), } var ( @@ -75,7 +76,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "BS", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "BS", "2020", "US", map[string]interface{}{ courier.ConfigUsername: "user1", courier.ConfigPassword: "pass1", diff --git a/handlers/chikka/chikka_test.go b/handlers/chikka/chikka_test.go index cc940d2a6..58c016fd7 100644 --- a/handlers/chikka/chikka_test.go +++ b/handlers/chikka/chikka_test.go @@ -7,10 +7,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "CK", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "CK", "2020", "US", nil), } var ( @@ -165,7 +166,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "CK", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "CK", "2020", "US", map[string]interface{}{ courier.ConfigPassword: "Password", courier.ConfigUsername: "Username", diff --git a/handlers/clickatell/clickatell_test.go b/handlers/clickatell/clickatell_test.go index a32c7da79..3bf2072ea 100644 --- a/handlers/clickatell/clickatell_test.go +++ b/handlers/clickatell/clickatell_test.go @@ -7,6 +7,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) // setSendURL takes care of setting the sendURL to call @@ -52,7 +53,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "CT", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "CT", "2020", "US", map[string]interface{}{ courier.ConfigAPIKey: "API-KEY", }) @@ -61,7 +62,7 @@ func TestSending(t *testing.T) { } var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "CT", "2020", "US", + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "CT", "2020", "US", map[string]interface{}{ courier.ConfigAPIKey: "12345", }), diff --git a/handlers/clickmobile/clickmobile_test.go b/handlers/clickmobile/clickmobile_test.go index be69ca267..4daa98925 100644 --- a/handlers/clickmobile/clickmobile_test.go +++ b/handlers/clickmobile/clickmobile_test.go @@ -7,6 +7,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/dates" ) @@ -62,7 +63,7 @@ var ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "CM", "2020", "MW", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "CM", "2020", "MW", nil), } var handleTestCases = []ChannelHandleTestCase{ @@ -93,7 +94,7 @@ func BenchmarkHandler(b *testing.B) { // setSendURL takes care of setting the sendURL to call func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { - c.(*courier.MockChannel).SetConfig(courier.ConfigSendURL, s.URL) + c.(*test.MockChannel).SetConfig(courier.ConfigSendURL, s.URL) sendURL = s.URL } @@ -130,7 +131,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "CM", "2020", "MW", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "CM", "2020", "MW", map[string]interface{}{ "password": "Password", "username": "Username", diff --git a/handlers/clicksend/clicksend_test.go b/handlers/clicksend/clicksend_test.go index c3e55c40e..25c10d20c 100644 --- a/handlers/clicksend/clicksend_test.go +++ b/handlers/clicksend/clicksend_test.go @@ -6,6 +6,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var ( @@ -13,7 +14,7 @@ var ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "CS", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "CS", "2020", "US", nil), } var handleTestCases = []ChannelHandleTestCase{ @@ -127,7 +128,7 @@ var sendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "GL", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "GL", "2020", "US", map[string]interface{}{ "username": "Aladdin", "password": "open sesame", diff --git a/handlers/dart/dart_test.go b/handlers/dart/dart_test.go index 3cc1449ff..68b0d7a94 100644 --- a/handlers/dart/dart_test.go +++ b/handlers/dart/dart_test.go @@ -6,10 +6,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var daTestChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "DA", "2020", "ID", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "DA", "2020", "ID", nil), } var ( @@ -97,7 +98,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultDAChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "DA", "2020", "ID", + var defaultDAChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "DA", "2020", "ID", map[string]interface{}{ courier.ConfigUsername: "Username", courier.ConfigPassword: "Password", diff --git a/handlers/discord/discord_test.go b/handlers/discord/discord_test.go index 4ef0e0be4..c742a273c 100644 --- a/handlers/discord/discord_test.go +++ b/handlers/discord/discord_test.go @@ -6,6 +6,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" "github.com/nyaruka/courier/utils" ) @@ -18,7 +19,7 @@ func BenchmarkHandler(b *testing.B) { } var testChannels = []courier.Channel{ - courier.NewMockChannel("bac782c2-7aeb-4389-92f5-97887744f573", "DS", "discord", "US", map[string]interface{}{}), + test.NewMockChannel("bac782c2-7aeb-4389-92f5-97887744f573", "DS", "discord", "US", map[string]interface{}{}), } var testCases = []ChannelHandleTestCase{ @@ -42,7 +43,7 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, // this is actually a path, which we'll combine with the test server URL sendURL := c.StringConfigForKey("send_path", "/discord/rp/send") sendURL, _ = utils.AddURLPath(s.URL, sendURL) - c.(*courier.MockChannel).SetConfig(courier.ConfigSendURL, sendURL) + c.(*test.MockChannel).SetConfig(courier.ConfigSendURL, sendURL) } func TestSending(t *testing.T) { diff --git a/handlers/dmark/dmark_test.go b/handlers/dmark/dmark_test.go index 08558dc1f..be1f2bfe6 100644 --- a/handlers/dmark/dmark_test.go +++ b/handlers/dmark/dmark_test.go @@ -7,10 +7,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "DM", "2020", "RW", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "DM", "2020", "RW", nil), } var ( @@ -80,7 +81,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AT", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AT", "2020", "US", map[string]interface{}{ courier.ConfigAuthToken: "Authy", }) diff --git a/handlers/external/external_test.go b/handlers/external/external_test.go index 798bd7d16..8bc2c0763 100644 --- a/handlers/external/external_test.go +++ b/handlers/external/external_test.go @@ -9,6 +9,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" "github.com/nyaruka/courier/utils" ) @@ -34,11 +35,11 @@ var ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", nil), } var gmChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "GM", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "GM", nil), } var handleTestCases = []ChannelHandleTestCase{ @@ -74,7 +75,7 @@ var handleTestCases = []ChannelHandleTestCase{ } var testSOAPReceiveChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ configTextXPath: "//content", configFromXPath: "//source", @@ -96,7 +97,7 @@ var gmTestCases = []ChannelHandleTestCase{ } var customChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ configMOFromField: "from_number", configMODateField: "timestamp", @@ -126,7 +127,7 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, // this is actually a path, which we'll combine with the test server URL sendURL := c.StringConfigForKey("send_path", "") sendURL, _ = utils.AddURLPath(s.URL, sendURL) - c.(*courier.MockChannel).SetConfig(courier.ConfigSendURL, sendURL) + c.(*test.MockChannel).SetConfig(courier.ConfigSendURL, sendURL) } var longSendTestCases = []ChannelSendTestCase{ @@ -390,38 +391,38 @@ var nationalGetSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var getChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + var getChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ "send_path": "?to={{to}}&text={{text}}&from={{from}}{{quick_replies}}", courier.ConfigSendMethod: http.MethodGet}) - var getSmartChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + var getSmartChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ "send_path": "?to={{to}}&text={{text}}&from={{from}}{{quick_replies}}", configEncoding: encodingSmart, courier.ConfigSendMethod: http.MethodGet}) - var postChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + var postChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ "send_path": "", courier.ConfigSendBody: "to={{to}}&text={{text}}&from={{from}}{{quick_replies}}", courier.ConfigSendMethod: http.MethodPost}) - var postChannelCustomContentType = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + var postChannelCustomContentType = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ "send_path": "", courier.ConfigSendBody: "to={{to_no_plus}}&text={{text}}&from={{from_no_plus}}{{quick_replies}}", courier.ConfigContentType: "application/x-www-form-urlencoded; charset=utf-8", courier.ConfigSendMethod: http.MethodPost}) - var postSmartChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + var postSmartChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ "send_path": "", courier.ConfigSendBody: "to={{to}}&text={{text}}&from={{from}}{{quick_replies}}", configEncoding: encodingSmart, courier.ConfigSendMethod: http.MethodPost}) - var jsonChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + var jsonChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ "send_path": "", courier.ConfigSendBody: `{ "to":{{to}}, "text":{{text}}, "from":{{from}}, "quick_replies":{{quick_replies}} }`, @@ -430,7 +431,7 @@ func TestSending(t *testing.T) { courier.ConfigSendHeaders: map[string]interface{}{"Authorization": "Token ABCDEF", "foo": "bar"}, }) - var xmlChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + var xmlChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ "send_path": "", courier.ConfigSendBody: `{{to}}{{text}}{{from}}{{quick_replies}}`, @@ -438,7 +439,7 @@ func TestSending(t *testing.T) { courier.ConfigSendMethod: http.MethodPut, }) - var xmlChannelWithResponseContent = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + var xmlChannelWithResponseContent = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ "send_path": "", courier.ConfigSendBody: `{{to}}{{text}}{{from}}{{quick_replies}}`, @@ -458,19 +459,19 @@ func TestSending(t *testing.T) { RunChannelSendTestCases(t, xmlChannel, newHandler(), xmlSendTestCases, nil) RunChannelSendTestCases(t, xmlChannelWithResponseContent, newHandler(), xmlSendWithResponseContentTestCases, nil) - var getChannel30IntLength = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + var getChannel30IntLength = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ "max_length": 30, "send_path": "?to={{to}}&text={{text}}&from={{from}}{{quick_replies}}", courier.ConfigSendMethod: http.MethodGet}) - var getChannel30StrLength = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + var getChannel30StrLength = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ "max_length": "30", "send_path": "?to={{to}}&text={{text}}&from={{from}}{{quick_replies}}", courier.ConfigSendMethod: http.MethodGet}) - var jsonChannel30IntLength = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + var jsonChannel30IntLength = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ "send_path": "", "max_length": 30, @@ -480,7 +481,7 @@ func TestSending(t *testing.T) { courier.ConfigSendHeaders: map[string]interface{}{"Authorization": "Token ABCDEF", "foo": "bar"}, }) - var xmlChannel30IntLength = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + var xmlChannel30IntLength = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ "send_path": "", "max_length": 30, @@ -495,7 +496,7 @@ func TestSending(t *testing.T) { RunChannelSendTestCases(t, jsonChannel30IntLength, newHandler(), jsonLongSendTestCases, nil) RunChannelSendTestCases(t, xmlChannel30IntLength, newHandler(), xmlLongSendTestCases, nil) - var nationalChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + var nationalChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ "send_path": "?to={{to}}&text={{text}}&from={{from}}{{quick_replies}}", "use_national": true, @@ -503,7 +504,7 @@ func TestSending(t *testing.T) { RunChannelSendTestCases(t, nationalChannel, newHandler(), nationalGetSendTestCases, nil) - var jsonChannelWithSendAuthorization = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + var jsonChannelWithSendAuthorization = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ "send_path": "", courier.ConfigSendBody: `{ "to":{{to}}, "text":{{text}}, "from":{{from}}, "quick_replies":{{quick_replies}} }`, diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index d1fe9d2c5..4de993ccf 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -13,11 +13,12 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/urns" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "FB", "1234", "", + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "FB", "1234", "", map[string]interface{}{courier.ConfigAuthToken: "a123", courier.ConfigSecret: "mysecret"}), } @@ -628,6 +629,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { // shorter max msg length for testing maxMsgLength = 100 - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "FB", "2020", "US", map[string]interface{}{courier.ConfigAuthToken: "access_token"}) + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "FB", "2020", "US", map[string]interface{}{courier.ConfigAuthToken: "access_token"}) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) } diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 7da61ba27..2b0179a2f 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -13,115 +13,116 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/urns" "github.com/stretchr/testify/assert" ) var testChannelsFBA = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "FBA", "12345", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "FBA", "12345", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}), } var testChannelsIG = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "IG", "12345", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "IG", "12345", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}), } var testChannelsWAC = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "WAC", "12345", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "WAC", "12345", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}), } var testCasesFBA = []ChannelHandleTestCase{ - {Label: "Receive Message FBA", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/helloMsgFBA.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + {Label: "Receive Message FBA", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, Text: Sp("Hello World"), URN: Sp("facebook:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Invalid Signature", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/helloMsgFBA.json")), Status: 400, Response: "invalid request signature", PrepRequest: addInvalidSignature}, + {Label: "Receive Invalid Signature", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), Status: 400, Response: "invalid request signature", PrepRequest: addInvalidSignature}, - {Label: "No Duplicate Receive Message", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/duplicateMsgFBA.json")), Status: 200, Response: "Handled", + {Label: "No Duplicate Receive Message", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/duplicateMsgFBA.json")), Status: 200, Response: "Handled", Text: Sp("Hello World"), URN: Sp("facebook:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Attachment", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/attachmentFBA.json")), Status: 200, Response: "Handled", + {Label: "Receive Attachment", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/attachmentFBA.json")), Status: 200, Response: "Handled", Text: Sp(""), Attachments: []string{"https://image-url/foo.png"}, URN: Sp("facebook:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Location", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/locationAttachment.json")), Status: 200, Response: "Handled", + {Label: "Receive Location", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/locationAttachment.json")), Status: 200, Response: "Handled", Text: Sp(""), Attachments: []string{"geo:1.200000,-1.300000"}, URN: Sp("facebook:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Thumbs Up", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/thumbsUp.json")), Status: 200, Response: "Handled", + {Label: "Receive Thumbs Up", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/thumbsUp.json")), Status: 200, Response: "Handled", Text: Sp("👍"), URN: Sp("facebook:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive OptIn UserRef", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/optInUserRef.json")), Status: 200, Response: "Handled", + {Label: "Receive OptIn UserRef", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/optInUserRef.json")), Status: 200, Response: "Handled", URN: Sp("facebook:ref:optin_user_ref"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, PrepRequest: addValidSignature}, - {Label: "Receive OptIn", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/optIn.json")), Status: 200, Response: "Handled", + {Label: "Receive OptIn", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/optIn.json")), Status: 200, Response: "Handled", URN: Sp("facebook:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, PrepRequest: addValidSignature}, - {Label: "Receive Get Started", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/postbackGetStarted.json")), Status: 200, Response: "Handled", + {Label: "Receive Get Started", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postbackGetStarted.json")), Status: 200, Response: "Handled", URN: Sp("facebook:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.NewConversation), ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, PrepRequest: addValidSignature}, - {Label: "Receive Referral Postback", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/postback.json")), Status: 200, Response: "Handled", + {Label: "Receive Referral Postback", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postback.json")), Status: 200, Response: "Handled", URN: Sp("facebook:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, PrepRequest: addValidSignature}, - {Label: "Receive Referral", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/postbackReferral.json")), Status: 200, Response: "Handled", + {Label: "Receive Referral", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postbackReferral.json")), Status: 200, Response: "Handled", URN: Sp("facebook:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, PrepRequest: addValidSignature}, - {Label: "Receive Referral", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/referral.json")), Status: 200, Response: `"referrer_id":"referral id"`, + {Label: "Receive Referral", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/referral.json")), Status: 200, Response: `"referrer_id":"referral id"`, URN: Sp("facebook:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, PrepRequest: addValidSignature}, - {Label: "Receive DLR", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/dlr.json")), Status: 200, Response: "Handled", + {Label: "Receive DLR", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/dlr.json")), Status: 200, Response: "Handled", Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), MsgStatus: Sp(courier.MsgDelivered), ExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233"), PrepRequest: addValidSignature}, - {Label: "Different Page", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/differentPageFBA.json")), Status: 200, Response: `"data":[]`, PrepRequest: addValidSignature}, - {Label: "Echo", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/echoFBA.json")), Status: 200, Response: `ignoring echo`, PrepRequest: addValidSignature}, - {Label: "Not Page", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/notPage.json")), Status: 400, Response: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notpage", PrepRequest: addValidSignature}, - {Label: "No Entries", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/noEntriesFBA.json")), Status: 400, Response: "no entries found", PrepRequest: addValidSignature}, - {Label: "No Messaging Entries", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/noMessagingEntriesFBA.json")), Status: 200, Response: "Handled", PrepRequest: addValidSignature}, - {Label: "Unknown Messaging Entry", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/unknownMessagingEntryFBA.json")), Status: 200, Response: "Handled", PrepRequest: addValidSignature}, + {Label: "Different Page", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/differentPageFBA.json")), Status: 200, Response: `"data":[]`, PrepRequest: addValidSignature}, + {Label: "Echo", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/echoFBA.json")), Status: 200, Response: `ignoring echo`, PrepRequest: addValidSignature}, + {Label: "Not Page", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/notPage.json")), Status: 400, Response: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notpage", PrepRequest: addValidSignature}, + {Label: "No Entries", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/noEntriesFBA.json")), Status: 400, Response: "no entries found", PrepRequest: addValidSignature}, + {Label: "No Messaging Entries", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/noMessagingEntriesFBA.json")), Status: 200, Response: "Handled", PrepRequest: addValidSignature}, + {Label: "Unknown Messaging Entry", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/unknownMessagingEntryFBA.json")), Status: 200, Response: "Handled", PrepRequest: addValidSignature}, {Label: "Not JSON", URL: "/c/fba/receive", Data: "not JSON", Status: 400, Response: "Error", PrepRequest: addValidSignature}, - {Label: "Invalid URN", URL: "/c/fba/receive", Data: string(courier.ReadFile("./testdata/fba/invalidURNFBA.json")), Status: 400, Response: "invalid facebook id", PrepRequest: addValidSignature}, + {Label: "Invalid URN", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/invalidURNFBA.json")), Status: 400, Response: "invalid facebook id", PrepRequest: addValidSignature}, } var testCasesIG = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: "/c/ig/receive", Data: string(courier.ReadFile("./testdata/ig/helloMsgIG.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + {Label: "Receive Message", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, Text: Sp("Hello World"), URN: Sp("instagram:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Invalid Signature", URL: "/c/ig/receive", Data: string(courier.ReadFile("./testdata/ig/helloMsgIG.json")), Status: 400, Response: "invalid request signature", PrepRequest: addInvalidSignature}, + {Label: "Receive Invalid Signature", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), Status: 400, Response: "invalid request signature", PrepRequest: addInvalidSignature}, - {Label: "No Duplicate Receive Message", URL: "/c/ig/receive", Data: string(courier.ReadFile("./testdata/ig/duplicateMsgIG.json")), Status: 200, Response: "Handled", + {Label: "No Duplicate Receive Message", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/duplicateMsgIG.json")), Status: 200, Response: "Handled", Text: Sp("Hello World"), URN: Sp("instagram:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Attachment", URL: "/c/ig/receive", Data: string(courier.ReadFile("./testdata/ig/attachmentIG.json")), Status: 200, Response: "Handled", + {Label: "Receive Attachment", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/attachmentIG.json")), Status: 200, Response: "Handled", Text: Sp(""), Attachments: []string{"https://image-url/foo.png"}, URN: Sp("instagram:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Like Heart", URL: "/c/ig/receive", Data: string(courier.ReadFile("./testdata/ig/like_heart.json")), Status: 200, Response: "Handled", + {Label: "Receive Like Heart", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/like_heart.json")), Status: 200, Response: "Handled", Text: Sp(""), URN: Sp("instagram:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Icebreaker Get Started", URL: "/c/ig/receive", Data: string(courier.ReadFile("./testdata/ig/icebreakerGetStarted.json")), Status: 200, Response: "Handled", + {Label: "Receive Icebreaker Get Started", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/icebreakerGetStarted.json")), Status: 200, Response: "Handled", URN: Sp("instagram:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.NewConversation), ChannelEventExtra: map[string]interface{}{"title": "icebreaker question", "payload": "get_started"}, PrepRequest: addValidSignature}, - {Label: "Different Page", URL: "/c/ig/receive", Data: string(courier.ReadFile("./testdata/ig/differentPageIG.json")), Status: 200, Response: `"data":[]`, PrepRequest: addValidSignature}, - {Label: "Echo", URL: "/c/ig/receive", Data: string(courier.ReadFile("./testdata/ig/echoIG.json")), Status: 200, Response: `ignoring echo`, PrepRequest: addValidSignature}, - {Label: "No Entries", URL: "/c/ig/receive", Data: string(courier.ReadFile("./testdata/ig/noEntriesIG.json")), Status: 400, Response: "no entries found", PrepRequest: addValidSignature}, - {Label: "Not Instagram", URL: "/c/ig/receive", Data: string(courier.ReadFile("./testdata/ig/notInstagram.json")), Status: 400, Response: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notinstagram", PrepRequest: addValidSignature}, - {Label: "No Messaging Entries", URL: "/c/ig/receive", Data: string(courier.ReadFile("./testdata/ig/noMessagingEntriesIG.json")), Status: 200, Response: "Handled", PrepRequest: addValidSignature}, - {Label: "Unknown Messaging Entry", URL: "/c/ig/receive", Data: string(courier.ReadFile("./testdata/ig/unknownMessagingEntryIG.json")), Status: 200, Response: "Handled", PrepRequest: addValidSignature}, + {Label: "Different Page", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/differentPageIG.json")), Status: 200, Response: `"data":[]`, PrepRequest: addValidSignature}, + {Label: "Echo", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/echoIG.json")), Status: 200, Response: `ignoring echo`, PrepRequest: addValidSignature}, + {Label: "No Entries", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/noEntriesIG.json")), Status: 400, Response: "no entries found", PrepRequest: addValidSignature}, + {Label: "Not Instagram", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/notInstagram.json")), Status: 400, Response: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notinstagram", PrepRequest: addValidSignature}, + {Label: "No Messaging Entries", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/noMessagingEntriesIG.json")), Status: 200, Response: "Handled", PrepRequest: addValidSignature}, + {Label: "Unknown Messaging Entry", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/unknownMessagingEntryIG.json")), Status: 200, Response: "Handled", PrepRequest: addValidSignature}, {Label: "Not JSON", URL: "/c/ig/receive", Data: "not JSON", Status: 400, Response: "Error", PrepRequest: addValidSignature}, - {Label: "Invalid URN", URL: "/c/ig/receive", Data: string(courier.ReadFile("./testdata/ig/invalidURNIG.json")), Status: 400, Response: "invalid instagram id", PrepRequest: addValidSignature}, - {Label: "Story Mention", URL: "/c/ig/receive", Data: string(courier.ReadFile("./testdata/ig/storyMentionIG.json")), Status: 200, Response: `ignoring story_mention`, PrepRequest: addValidSignature}, - {Label: "Message unsent", URL: "/c/ig/receive", Data: string(courier.ReadFile("./testdata/ig/unsentMsgIG.json")), Status: 200, Response: `msg deleted`, PrepRequest: addValidSignature}, + {Label: "Invalid URN", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/invalidURNIG.json")), Status: 400, Response: "invalid instagram id", PrepRequest: addValidSignature}, + {Label: "Story Mention", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/storyMentionIG.json")), Status: 200, Response: `ignoring story_mention`, PrepRequest: addValidSignature}, + {Label: "Message unsent", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/unsentMsgIG.json")), Status: 200, Response: `msg deleted`, PrepRequest: addValidSignature}, } func addValidSignature(r *http.Request) { @@ -236,49 +237,49 @@ func TestDescribeWAC(t *testing.T) { var wacReceiveURL = "/c/wac/receive" var testCasesWAC = []ChannelHandleTestCase{ - {Label: "Receive Message WAC", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/helloWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + {Label: "Receive Message WAC", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/helloWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, Text: Sp("Hello World"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Duplicate Valid Message", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/duplicateWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + {Label: "Receive Duplicate Valid Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/duplicateWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, Text: Sp("Hello World"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Voice Message", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/voiceWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + {Label: "Receive Valid Voice Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/voiceWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, Text: Sp(""), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Attachment: Sp("https://foo.bar/attachmentURL_Voice"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Button Message", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/buttonWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + {Label: "Receive Valid Button Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/buttonWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, Text: Sp("No"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Document Message", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/documentWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + {Label: "Receive Valid Document Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/documentWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, Text: Sp("80skaraokesonglistartist"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Attachment: Sp("https://foo.bar/attachmentURL_Document"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Image Message", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/imageWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + {Label: "Receive Valid Image Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/imageWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, Text: Sp("Check out my new phone!"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Attachment: Sp("https://foo.bar/attachmentURL_Image"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Video Message", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/videoWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + {Label: "Receive Valid Video Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/videoWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, Text: Sp("Check out my new phone!"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Attachment: Sp("https://foo.bar/attachmentURL_Video"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Audio Message", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/audioWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + {Label: "Receive Valid Audio Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/audioWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, Text: Sp("Check out my new phone!"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Attachment: Sp("https://foo.bar/attachmentURL_Audio"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Location Message", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/locationWAC.json")), Status: 200, Response: `"type":"msg"`, + {Label: "Receive Valid Location Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/locationWAC.json")), Status: 200, Response: `"type":"msg"`, Text: Sp(""), Attachment: Sp("geo:0.000000,1.000000"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, {Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: "not json", Status: 400, Response: "unable to parse", PrepRequest: addValidSignature}, - {Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/invalidFrom.json")), Status: 400, Response: "invalid whatsapp id", PrepRequest: addValidSignature}, - {Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/invalidTimestamp.json")), Status: 400, Response: "invalid timestamp", PrepRequest: addValidSignature}, + {Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidFrom.json")), Status: 400, Response: "invalid whatsapp id", PrepRequest: addValidSignature}, + {Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidTimestamp.json")), Status: 400, Response: "invalid timestamp", PrepRequest: addValidSignature}, - {Label: "Receive Valid Status", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/validStatusWAC.json")), Status: 200, Response: `"type":"status"`, + {Label: "Receive Valid Status", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/validStatusWAC.json")), Status: 200, Response: `"type":"status"`, MsgStatus: Sp("S"), ExternalID: Sp("external_id"), PrepRequest: addValidSignature}, - {Label: "Receive Invalid Status", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/invalidStatusWAC.json")), Status: 400, Response: `"unknown status: in_orbit"`, PrepRequest: addValidSignature}, - {Label: "Receive Ignore Status", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/ignoreStatusWAC.json")), Status: 200, Response: `"ignoring status: deleted"`, PrepRequest: addValidSignature}, - {Label: "Receive Valid Interactive Button Reply Message", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/buttonReplyWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + {Label: "Receive Invalid Status", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidStatusWAC.json")), Status: 400, Response: `"unknown status: in_orbit"`, PrepRequest: addValidSignature}, + {Label: "Receive Ignore Status", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/ignoreStatusWAC.json")), Status: 200, Response: `"ignoring status: deleted"`, PrepRequest: addValidSignature}, + {Label: "Receive Valid Interactive Button Reply Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/buttonReplyWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, Text: Sp("Yes"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Interactive List Reply Message", URL: wacReceiveURL, Data: string(courier.ReadFile("./testdata/wac/listReplyWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + {Label: "Receive Valid Interactive List Reply Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/listReplyWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, Text: Sp("Yes"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, } @@ -862,9 +863,9 @@ func TestSending(t *testing.T) { // shorter max msg length for testing maxMsgLength = 100 - var ChannelFBA = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "FBA", "12345", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}) - var ChannelIG = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "IG", "12345", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}) - var ChannelWAC = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WAC", "12345_ID", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}) + var ChannelFBA = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "FBA", "12345", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}) + var ChannelIG = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "IG", "12345", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}) + var ChannelWAC = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WAC", "12345_ID", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}) RunChannelSendTestCases(t, ChannelFBA, newHandler("FBA", "Facebook", false), SendTestCasesFBA, nil) RunChannelSendTestCases(t, ChannelIG, newHandler("IG", "Instagram", false), SendTestCasesIG, nil) @@ -900,7 +901,7 @@ func newServer(backend courier.Backend) courier.Server { } func TestBuildMediaRequest(t *testing.T) { - mb := courier.NewMockBackend() + mb := test.NewMockBackend() s := newServer(mb) wacHandler := &handler{NewBaseHandlerWithParams(courier.ChannelType("WAC"), "WhatsApp Cloud", false)} wacHandler.Initialize(s) diff --git a/handlers/firebase/firebase_test.go b/handlers/firebase/firebase_test.go index 752ef020f..9bd0f76f9 100644 --- a/handlers/firebase/firebase_test.go +++ b/handlers/firebase/firebase_test.go @@ -7,6 +7,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var ( @@ -35,12 +36,12 @@ Duis eu arcu pharetra, laoreet nunc at, pharetra sapien. Nulla eu libero diam. Donec euismod dapibus ligula, sit amet hendrerit neque vulputate ac.` var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "FCM", "1234", "", + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "FCM", "1234", "", map[string]interface{}{ configKey: "FCMKey", configTitle: "FCMTitle", }), - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "FCM", "1234", "", + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "FCM", "1234", "", map[string]interface{}{ configKey: "FCMKey", configNotification: true, diff --git a/handlers/freshchat/freshchat_test.go b/handlers/freshchat/freshchat_test.go index e27322753..87c07e718 100644 --- a/handlers/freshchat/freshchat_test.go +++ b/handlers/freshchat/freshchat_test.go @@ -7,10 +7,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "FC", "2020", "US", map[string]interface{}{ + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "FC", "2020", "US", map[string]interface{}{ "username": "c8fddfaf-622a-4a0e-b060-4f3ccbeab606", //agent_id "secret": cert, // public_key for sig "auth_token": "authtoken", //API bearer token @@ -119,7 +120,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "FC", "2020", "US", map[string]interface{}{ + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "FC", "2020", "US", map[string]interface{}{ "username": "c8fddfaf-622a-4a0e-b060-4f3ccbeab606", "secret": cert, "auth_token": "enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", diff --git a/handlers/globe/globe_test.go b/handlers/globe/globe_test.go index 5da95b16c..8548108d9 100644 --- a/handlers/globe/globe_test.go +++ b/handlers/globe/globe_test.go @@ -7,6 +7,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var ( @@ -107,7 +108,7 @@ var ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "GL", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "GL", "2020", "US", nil), } var handleTestCases = []ChannelHandleTestCase{ @@ -160,7 +161,7 @@ var sendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "GL", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "GL", "2020", "US", map[string]interface{}{ "app_id": "12345", "app_secret": "mysecret", diff --git a/handlers/highconnection/highconnection_test.go b/handlers/highconnection/highconnection_test.go index 2492f6220..4bd0bce3f 100644 --- a/handlers/highconnection/highconnection_test.go +++ b/handlers/highconnection/highconnection_test.go @@ -7,10 +7,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "HX", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "HX", "2020", "US", nil), } var ( @@ -153,7 +154,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "HX", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "HX", "2020", "US", map[string]interface{}{ courier.ConfigPassword: "Password", courier.ConfigUsername: "Username", diff --git a/handlers/hormuud/hormuud_test.go b/handlers/hormuud/hormuud_test.go index 9a38efb9f..e4d302a61 100644 --- a/handlers/hormuud/hormuud_test.go +++ b/handlers/hormuud/hormuud_test.go @@ -8,6 +8,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var ( @@ -21,7 +22,7 @@ var ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "HM", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "HM", "2020", "US", nil), } var handleTestCases = []ChannelHandleTestCase{ @@ -93,7 +94,7 @@ func TestSending(t *testing.T) { tokenURL = server.URL + "?valid=true" - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "HM", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "HM", "2020", "US", map[string]interface{}{ "username": "foo@bar.com", "password": "sesame", diff --git a/handlers/http_test.go b/handlers/http_test.go index 80c4123c8..64ab44ccc 100644 --- a/handlers/http_test.go +++ b/handlers/http_test.go @@ -6,6 +6,7 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/urns" "github.com/stretchr/testify/assert" @@ -20,8 +21,8 @@ func TestDoHTTPRequest(t *testing.T) { })) defer httpx.SetRequestor(httpx.DefaultRequestor) - mb := courier.NewMockBackend() - mc := courier.NewMockChannel("7a8ff1d4-f211-4492-9d05-e1905f6da8c8", "NX", "1234", "EC", nil) + mb := test.NewMockBackend() + mc := test.NewMockChannel("7a8ff1d4-f211-4492-9d05-e1905f6da8c8", "NX", "1234", "EC", nil) mm := mb.NewOutgoingMsg(mc, courier.NewMsgID(123), urns.URN("tel:+1234"), "Hello World", false, nil, "", "") logger := courier.NewChannelLoggerForSend(mm) diff --git a/handlers/i2sms/i2sms_test.go b/handlers/i2sms/i2sms_test.go index 0641b4c79..b06da3b17 100644 --- a/handlers/i2sms/i2sms_test.go +++ b/handlers/i2sms/i2sms_test.go @@ -6,10 +6,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "I2", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "I2", "2020", "US", nil), } var ( @@ -67,7 +68,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "I2", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "I2", "2020", "US", map[string]interface{}{ courier.ConfigUsername: "user1", courier.ConfigPassword: "pass1", diff --git a/handlers/infobip/infobip_test.go b/handlers/infobip/infobip_test.go index 2c3503f6d..4168a3195 100644 --- a/handlers/infobip/infobip_test.go +++ b/handlers/infobip/infobip_test.go @@ -7,10 +7,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "IB", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "IB", "2020", "US", nil), } var receiveURL = "/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" @@ -291,7 +292,7 @@ var transSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "IB", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "IB", "2020", "US", map[string]interface{}{ courier.ConfigPassword: "Password", courier.ConfigUsername: "Username", @@ -299,7 +300,7 @@ func TestSending(t *testing.T) { RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) - var transChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "IB", "2020", "US", + var transChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "IB", "2020", "US", map[string]interface{}{ courier.ConfigPassword: "Password", courier.ConfigUsername: "Username", diff --git a/handlers/jasmin/jasmin_test.go b/handlers/jasmin/jasmin_test.go index 49a1d673b..523dd8092 100644 --- a/handlers/jasmin/jasmin_test.go +++ b/handlers/jasmin/jasmin_test.go @@ -7,6 +7,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var ( @@ -22,7 +23,7 @@ var ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JS", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JS", "2020", "US", nil), } var handleTestCases = []ChannelHandleTestCase{ @@ -52,7 +53,7 @@ func BenchmarkHandler(b *testing.B) { // setSendURL takes care of setting the send_url to our test server host func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { - c.(*courier.MockChannel).SetConfig("send_url", s.URL) + c.(*test.MockChannel).SetConfig("send_url", s.URL) } var defaultSendTestCases = []ChannelSendTestCase{ @@ -91,7 +92,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JS", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JS", "2020", "US", map[string]interface{}{ "password": "Password", "username": "Username"}) diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index e39f25116..1f2528aa3 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -16,6 +16,7 @@ import ( "time" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/urns" "github.com/sirupsen/logrus" @@ -26,7 +27,7 @@ import ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JC", "2020", "US", map[string]interface{}{configAppSecret: "secret", configAppID: "app-id"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JC", "2020", "US", map[string]interface{}{configAppSecret: "secret", configAppID: "app-id"}), } var ( @@ -258,7 +259,7 @@ func TestDescribe(t *testing.T) { JCAPI := buildMockJCAPI(testCases) defer JCAPI.Close() - mb := courier.NewMockBackend() + mb := test.NewMockBackend() conn := mb.RedisPool().Get() _, err := conn.Do("SET", "jiochat_channel_access_token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ACCESS_TOKEN") @@ -287,7 +288,7 @@ func TestDescribe(t *testing.T) { } func TestBuildMediaRequest(t *testing.T) { - mb := courier.NewMockBackend() + mb := test.NewMockBackend() conn := mb.RedisPool().Get() _, err := conn.Do("SET", "jiochat_channel_access_token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ACCESS_TOKEN") @@ -373,7 +374,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL}, } -func setupBackend(mb *courier.MockBackend) { +func setupBackend(mb *test.MockBackend) { conn := mb.RedisPool().Get() _, err := conn.Do("SET", "jiochat_channel_access_token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ACCESS_TOKEN") @@ -386,6 +387,6 @@ func setupBackend(mb *courier.MockBackend) { func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JC", "2020", "US", map[string]interface{}{configAppSecret: "secret", configAppID: "app-id"}) + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JC", "2020", "US", map[string]interface{}{configAppSecret: "secret", configAppID: "app-id"}) RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, setupBackend) } diff --git a/handlers/junebug/junebug_test.go b/handlers/junebug/junebug_test.go index 0e65179d5..6c7f670dd 100644 --- a/handlers/junebug/junebug_test.go +++ b/handlers/junebug/junebug_test.go @@ -7,15 +7,16 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) -var testChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JN", "2020", "US", map[string]interface{}{ +var testChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JN", "2020", "US", map[string]interface{}{ "username": "user1", "password": "pass1", "send_url": "https://foo.bar/", }) -var authenticatedTestChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JN", "2020", "US", map[string]interface{}{ +var authenticatedTestChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JN", "2020", "US", map[string]interface{}{ "username": "user1", "password": "pass1", "send_url": "https://foo.bar/", @@ -142,7 +143,7 @@ func BenchmarkHandler(b *testing.B) { } func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { - c.(*courier.MockChannel).SetConfig("send_url", s.URL) + c.(*test.MockChannel).SetConfig("send_url", s.URL) } var sendTestCases = []ChannelSendTestCase{ diff --git a/handlers/kaleyra/kaleyra_test.go b/handlers/kaleyra/kaleyra_test.go index b30ad53ed..6cf19bb90 100644 --- a/handlers/kaleyra/kaleyra_test.go +++ b/handlers/kaleyra/kaleyra_test.go @@ -8,6 +8,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) const ( @@ -17,7 +18,7 @@ const ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "KWA", "250788383383", "", + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "KWA", "250788383383", "", map[string]interface{}{ configAccountSID: "SID", configApiKey: "123456", diff --git a/handlers/kannel/kannel_test.go b/handlers/kannel/kannel_test.go index 74b357672..8cb77c1d0 100644 --- a/handlers/kannel/kannel_test.go +++ b/handlers/kannel/kannel_test.go @@ -7,6 +7,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var ( @@ -23,11 +24,11 @@ var ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "KN", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "KN", "2020", "US", nil), } var ignoreChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "KN", "2020", "US", map[string]interface{}{"ignore_sent": true}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "KN", "2020", "US", map[string]interface{}{"ignore_sent": true}), } var handleTestCases = []ChannelHandleTestCase{ @@ -63,12 +64,12 @@ func BenchmarkHandler(b *testing.B) { // setSendURL takes care of setting the send_url to our test server host func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { - c.(*courier.MockChannel).SetConfig("send_url", s.URL) + c.(*test.MockChannel).SetConfig("send_url", s.URL) } // setSendURLWithQuery takes care of setting the send_url to our test server host func setSendURLWithQuery(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { - c.(*courier.MockChannel).SetConfig("send_url", s.URL+"?auth=foo") + c.(*test.MockChannel).SetConfig("send_url", s.URL+"?auth=foo") } var defaultSendTestCases = []ChannelSendTestCase{ @@ -127,12 +128,12 @@ var nationalSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "KN", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "KN", "2020", "US", map[string]interface{}{ "password": "Password", "username": "Username"}) - var nationalChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "KN", "2020", "US", + var nationalChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "KN", "2020", "US", map[string]interface{}{ "password": "Password", "username": "Username", diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index 46bb77f6a..581cea581 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -9,6 +9,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" "github.com/stretchr/testify/assert" ) @@ -248,7 +249,7 @@ var noEvent = `{ }` var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "LN", "2020", "US", + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "LN", "2020", "US", map[string]interface{}{ "secret": "Secret", "auth_token": "the-auth-token", @@ -448,7 +449,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "LN", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "LN", "2020", "US", map[string]interface{}{ "auth_token": "AccessToken", }, @@ -458,7 +459,7 @@ func TestSending(t *testing.T) { } func TestBuildMediaRequest(t *testing.T) { - mb := courier.NewMockBackend() + mb := test.NewMockBackend() lnHandler := &handler{NewBaseHandler(courier.ChannelType("LN"), "Line")} req, _ := lnHandler.BuildDownloadMediaRequest(context.Background(), mb, testChannels[0], "https://example.org/v1/media/41") diff --git a/handlers/m3tech/m3tech_test.go b/handlers/m3tech/m3tech_test.go index aecd13dce..e76f32429 100644 --- a/handlers/m3tech/m3tech_test.go +++ b/handlers/m3tech/m3tech_test.go @@ -6,6 +6,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var ( @@ -15,7 +16,7 @@ var ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "M3", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "M3", "2020", "US", nil), } var handleTestCases = []ChannelHandleTestCase{ @@ -82,7 +83,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "M3", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "M3", "2020", "US", map[string]interface{}{ "password": "Password", "username": "Username", diff --git a/handlers/macrokiosk/macrokiosk_test.go b/handlers/macrokiosk/macrokiosk_test.go index 0190fc1e4..bad397c85 100644 --- a/handlers/macrokiosk/macrokiosk_test.go +++ b/handlers/macrokiosk/macrokiosk_test.go @@ -7,10 +7,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MK", "2020", "MY", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MK", "2020", "MY", nil), } var ( @@ -128,7 +129,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MK", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MK", "2020", "US", map[string]interface{}{ "password": "Password", "username": "Username", diff --git a/handlers/mblox/mblox_test.go b/handlers/mblox/mblox_test.go index 8bdf97611..43b53c007 100644 --- a/handlers/mblox/mblox_test.go +++ b/handlers/mblox/mblox_test.go @@ -7,10 +7,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MB", "2020", "BR", map[string]interface{}{"username": "zv-username", "password": "zv-password"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MB", "2020", "BR", map[string]interface{}{"username": "zv-username", "password": "zv-password"}), } var ( @@ -156,7 +157,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MB", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MB", "2020", "US", map[string]interface{}{ "password": "Password", "username": "Username", diff --git a/handlers/media_test.go b/handlers/media_test.go index a6d5b2b9a..56dfd67ad 100644 --- a/handlers/media_test.go +++ b/handlers/media_test.go @@ -6,22 +6,23 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" "github.com/stretchr/testify/assert" ) func TestResolveAttachments(t *testing.T) { ctx := context.Background() - mb := courier.NewMockBackend() + mb := test.NewMockBackend() - imageJPG := courier.NewMockMedia("test.jpg", "image/jpeg", "http://mock.com/1234/test.jpg", 1024*1024, 640, 480, 0, nil) + imageJPG := test.NewMockMedia("test.jpg", "image/jpeg", "http://mock.com/1234/test.jpg", 1024*1024, 640, 480, 0, nil) - audioM4A := courier.NewMockMedia("test.m4a", "audio/mp4", "http://mock.com/2345/test.m4a", 1024*1024, 0, 0, 200, nil) - audioMP3 := courier.NewMockMedia("test.mp3", "audio/mp3", "http://mock.com/3456/test.mp3", 1024*1024, 0, 0, 200, []courier.Media{audioM4A}) + audioM4A := test.NewMockMedia("test.m4a", "audio/mp4", "http://mock.com/2345/test.m4a", 1024*1024, 0, 0, 200, nil) + audioMP3 := test.NewMockMedia("test.mp3", "audio/mp3", "http://mock.com/3456/test.mp3", 1024*1024, 0, 0, 200, []courier.Media{audioM4A}) - thumbJPG := courier.NewMockMedia("test.jpg", "image/jpeg", "http://mock.com/4567/test.jpg", 1024*1024, 640, 480, 0, nil) - videoMP4 := courier.NewMockMedia("test.mp4", "video/mp4", "http://mock.com/5678/test.mp4", 1024*1024, 0, 0, 1000, []courier.Media{thumbJPG}) + thumbJPG := test.NewMockMedia("test.jpg", "image/jpeg", "http://mock.com/4567/test.jpg", 1024*1024, 640, 480, 0, nil) + videoMP4 := test.NewMockMedia("test.mp4", "video/mp4", "http://mock.com/5678/test.mp4", 1024*1024, 0, 0, 1000, []courier.Media{thumbJPG}) - videoMOV := courier.NewMockMedia("test.mov", "video/quicktime", "http://mock.com/6789/test.mov", 100*1024*1024, 0, 0, 2000, nil) + videoMOV := test.NewMockMedia("test.mov", "video/quicktime", "http://mock.com/6789/test.mov", 100*1024*1024, 0, 0, 2000, nil) mb.MockMedia(imageJPG) mb.MockMedia(audioMP3) diff --git a/handlers/messangi/messangi_test.go b/handlers/messangi/messangi_test.go index bde778662..f2967ecd4 100644 --- a/handlers/messangi/messangi_test.go +++ b/handlers/messangi/messangi_test.go @@ -6,10 +6,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MG", "2020", "JM", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MG", "2020", "JM", nil), } var ( @@ -73,7 +74,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MG", "2020", "JM", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MG", "2020", "JM", map[string]interface{}{ "public_key": "my-public-key", "private_key": "my-private-key", diff --git a/handlers/mtarget/mtarget_test.go b/handlers/mtarget/mtarget_test.go index 7453c887e..69a2388bf 100644 --- a/handlers/mtarget/mtarget_test.go +++ b/handlers/mtarget/mtarget_test.go @@ -6,6 +6,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var ( @@ -27,7 +28,7 @@ var ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MT", "2020", "FR", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MT", "2020", "FR", nil), } var handleTestCases = []ChannelHandleTestCase{ @@ -101,7 +102,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MT", "2020", "FR", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MT", "2020", "FR", map[string]interface{}{ "password": "Password", "username": "Username", diff --git a/handlers/nexmo/nexmo_test.go b/handlers/nexmo/nexmo_test.go index 5a434e0ad..305b18622 100644 --- a/handlers/nexmo/nexmo_test.go +++ b/handlers/nexmo/nexmo_test.go @@ -6,10 +6,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "NX", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "NX", "2020", "US", nil), } var ( @@ -112,7 +113,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "NX", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "NX", "2020", "US", map[string]interface{}{ configNexmoAPIKey: "nexmo-api-key", configNexmoAPISecret: "nexmo-api-secret", diff --git a/handlers/novo/novo_test.go b/handlers/novo/novo_test.go index c49d77283..5795c6703 100644 --- a/handlers/novo/novo_test.go +++ b/handlers/novo/novo_test.go @@ -6,10 +6,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "NV", "2020", "TT", map[string]interface{}{ + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "NV", "2020", "TT", map[string]interface{}{ "merchant_id": "my-merchant-id", "merchant_secret": "my-merchant-secret", "secret": "sesame", @@ -81,7 +82,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "NV", "2020", "TT", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "NV", "2020", "TT", map[string]interface{}{ "merchant_id": "my-merchant-id", "merchant_secret": "my-merchant-secret", diff --git a/handlers/playmobile/playmobile_test.go b/handlers/playmobile/playmobile_test.go index 03ee4180e..04d73f60c 100644 --- a/handlers/playmobile/playmobile_test.go +++ b/handlers/playmobile/playmobile_test.go @@ -6,10 +6,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "PM", "1122", "UZ", map[string]interface{}{ + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "PM", "1122", "UZ", map[string]interface{}{ "incoming_prefixes": []string{"abc", "DE"}, }), } @@ -179,7 +180,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "PM", "1122", "UZ", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "PM", "1122", "UZ", map[string]interface{}{ "password": "Password", "username": "Username", diff --git a/handlers/plivo/plivo_test.go b/handlers/plivo/plivo_test.go index 49f77ce92..3b879ef46 100644 --- a/handlers/plivo/plivo_test.go +++ b/handlers/plivo/plivo_test.go @@ -6,10 +6,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "PL", "2020", "MY", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "PL", "2020", "MY", nil), } var ( @@ -123,7 +124,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "PL", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "PL", "2020", "US", map[string]interface{}{ configPlivoAuthID: "AuthID", configPlivoAuthToken: "AuthToken", diff --git a/handlers/redrabbit/redrabbit_test.go b/handlers/redrabbit/redrabbit_test.go index cbcf7b681..971996244 100644 --- a/handlers/redrabbit/redrabbit_test.go +++ b/handlers/redrabbit/redrabbit_test.go @@ -6,6 +6,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) // setSendURL takes care of setting the send_url to our test server host @@ -97,7 +98,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "RR", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "RR", "2020", "US", map[string]interface{}{ "password": "Password", "username": "Username", diff --git a/handlers/rocketchat/rocketchat_test.go b/handlers/rocketchat/rocketchat_test.go index 309d4314e..d24048f78 100644 --- a/handlers/rocketchat/rocketchat_test.go +++ b/handlers/rocketchat/rocketchat_test.go @@ -6,6 +6,7 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) const ( @@ -14,7 +15,7 @@ const ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "RC", "1234", "", + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "RC", "1234", "", map[string]interface{}{ configBaseURL: "https://my.rocket.chat/api/apps/public/684202ed-1461-4983-9ea7-fde74b15026c", configSecret: "123456789", @@ -104,7 +105,7 @@ func BenchmarkHandler(b *testing.B) { } func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { - c.(*courier.MockChannel).SetConfig(configBaseURL, s.URL) + c.(*test.MockChannel).SetConfig(configBaseURL, s.URL) } var sendTestCases = []handlers.ChannelSendTestCase{ diff --git a/handlers/shaqodoon/shaqodoon_test.go b/handlers/shaqodoon/shaqodoon_test.go index 428f2b42f..decbead78 100644 --- a/handlers/shaqodoon/shaqodoon_test.go +++ b/handlers/shaqodoon/shaqodoon_test.go @@ -7,6 +7,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var ( @@ -22,7 +23,7 @@ var ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SQ", "2020", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SQ", "2020", "US", nil), } var handleTestCases = []ChannelHandleTestCase{ @@ -51,7 +52,7 @@ func BenchmarkHandler(b *testing.B) { } func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { - c.(*courier.MockChannel).SetConfig(courier.ConfigSendURL, s.URL) + c.(*test.MockChannel).SetConfig(courier.ConfigSendURL, s.URL) } var getSendTestCases = []ChannelSendTestCase{ @@ -82,7 +83,7 @@ var getSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var getChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SQ", "2020", "US", + var getChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SQ", "2020", "US", map[string]interface{}{ courier.ConfigSendURL: "SendURL", courier.ConfigPassword: "Password", diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 9a4236f9c..531293bf5 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -13,6 +13,7 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/urns" "github.com/stretchr/testify/assert" ) @@ -23,7 +24,7 @@ const ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel(channelUUID, "SL", "2022", "US", map[string]interface{}{"bot_token": "xoxb-abc123", "verification_token": "one-long-verification-token"}), + test.NewMockChannel(channelUUID, "SL", "2022", "US", map[string]interface{}{"bot_token": "xoxb-abc123", "verification_token": "one-long-verification-token"}), } const helloMsg = `{ diff --git a/handlers/smscentral/smscentral_test.go b/handlers/smscentral/smscentral_test.go index e89caf047..72d886932 100644 --- a/handlers/smscentral/smscentral_test.go +++ b/handlers/smscentral/smscentral_test.go @@ -6,6 +6,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var ( @@ -18,7 +19,7 @@ var ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SC", "2020", "US", map[string]interface{}{"username": "Username", "password": "Password"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SC", "2020", "US", map[string]interface{}{"username": "Username", "password": "Password"}), } var handleTestCases = []ChannelHandleTestCase{ @@ -72,7 +73,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SC", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SC", "2020", "US", map[string]interface{}{ courier.ConfigPassword: "Password", courier.ConfigUsername: "Username", diff --git a/handlers/start/start_test.go b/handlers/start/start_test.go index 70a177c1d..118b36f7e 100644 --- a/handlers/start/start_test.go +++ b/handlers/start/start_test.go @@ -7,10 +7,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ST", "2020", "UA", map[string]interface{}{"username": "st-username", "password": "st-password"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ST", "2020", "UA", map[string]interface{}{"username": "st-username", "password": "st-password"}), } var ( @@ -169,6 +170,6 @@ var defaultSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ST", "2020", "UA", map[string]interface{}{"username": "Username", "password": "Password"}) + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ST", "2020", "UA", map[string]interface{}{"username": "Username", "password": "Password"}) RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) } diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index 76e6e1e5e..2969eb41a 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -10,10 +10,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "TG", "2020", "US", map[string]interface{}{"auth_token": "a123"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "TG", "2020", "US", map[string]interface{}{"auth_token": "a123"}), } var helloMsg = `{ @@ -714,7 +715,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TG", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TG", "2020", "US", map[string]interface{}{courier.ConfigAuthToken: "auth_token"}) RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) diff --git a/handlers/telesom/telesom_test.go b/handlers/telesom/telesom_test.go index 2cd9cc8b0..1c0b8370e 100644 --- a/handlers/telesom/telesom_test.go +++ b/handlers/telesom/telesom_test.go @@ -7,6 +7,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/dates" ) @@ -18,7 +19,7 @@ var ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TS", "2020", "SO", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TS", "2020", "SO", nil), } var handleTestCases = []ChannelHandleTestCase{ @@ -45,7 +46,7 @@ func BenchmarkHandler(b *testing.B) { // setSendURL takes care of setting the sendURL to call func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { - c.(*courier.MockChannel).SetConfig(courier.ConfigSendURL, s.URL) + c.(*test.MockChannel).SetConfig(courier.ConfigSendURL, s.URL) sendURL = s.URL } @@ -82,7 +83,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TS", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TS", "2020", "US", map[string]interface{}{ "password": "Password", "username": "Username", diff --git a/handlers/test.go b/handlers/test.go index 6cf301395..1916eea77 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -16,6 +16,7 @@ import ( _ "github.com/lib/pq" // postgres driver "github.com/nyaruka/courier" + "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/urns" "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" @@ -207,8 +208,8 @@ func newServer(backend courier.Backend) courier.Server { } // RunChannelSendTestCases runs all the passed in test cases against the channel -func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler courier.ChannelHandler, testCases []ChannelSendTestCase, setupBackend func(*courier.MockBackend)) { - mb := courier.NewMockBackend() +func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler courier.ChannelHandler, testCases []ChannelSendTestCase, setupBackend func(*test.MockBackend)) { + mb := test.NewMockBackend() if setupBackend != nil { setupBackend(mb) } @@ -363,7 +364,7 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour // RunChannelTestCases runs all the passed in tests cases for the passed in channel configurations func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler courier.ChannelHandler, testCases []ChannelHandleTestCase) { - mb := courier.NewMockBackend() + mb := test.NewMockBackend() s := newServer(mb) for _, ch := range channels { @@ -475,7 +476,7 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri // RunChannelBenchmarks runs all the passed in test cases for the passed in channels func RunChannelBenchmarks(b *testing.B, channels []courier.Channel, handler courier.ChannelHandler, testCases []ChannelHandleTestCase) { - mb := courier.NewMockBackend() + mb := test.NewMockBackend() s := newServer(mb) for _, ch := range channels { diff --git a/handlers/thinq/thinq_test.go b/handlers/thinq/thinq_test.go index af01fe9c2..f3a80bb39 100644 --- a/handlers/thinq/thinq_test.go +++ b/handlers/thinq/thinq_test.go @@ -6,10 +6,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TQ", "+12065551212", "US", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TQ", "+12065551212", "US", nil), } var ( @@ -82,7 +83,7 @@ var sendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var channel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TQ", "+12065551212", "US", + var channel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TQ", "+12065551212", "US", map[string]interface{}{ configAccountID: "1234", configAPITokenUser: "user1", diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index c44b29b16..373712ff9 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -9,23 +9,24 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/urns" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "T", "2020", "US", map[string]interface{}{"auth_token": "6789"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "T", "2020", "US", map[string]interface{}{"auth_token": "6789"}), } var tmsTestChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TMS", "2020", "US", map[string]interface{}{"auth_token": "6789"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TMS", "2020", "US", map[string]interface{}{"auth_token": "6789"}), } var twTestChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TW", "2020", "US", map[string]interface{}{"auth_token": "6789"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TW", "2020", "US", map[string]interface{}{"auth_token": "6789"}), } var swTestChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SW", "2020", "US", map[string]interface{}{"auth_token": "6789"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SW", "2020", "US", map[string]interface{}{"auth_token": "6789"}), } var ( @@ -255,7 +256,7 @@ func TestHandler(t *testing.T) { RunChannelTestCases(t, twTestChannels, newTWIMLHandler("TW", "TwiML API", true), twTestCases) RunChannelTestCases(t, swTestChannels, newTWIMLHandler("SW", "SignalWire", false), swTestCases) - waChannel := courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SW", "+12065551212", "US", + waChannel := test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SW", "+12065551212", "US", map[string]interface{}{ configAccountSID: "accountSID", courier.ConfigAuthToken: "6789", @@ -264,7 +265,7 @@ func TestHandler(t *testing.T) { waChannel.SetScheme(urns.WhatsAppScheme) RunChannelTestCases(t, []courier.Channel{waChannel}, newTWIMLHandler("T", "TwilioWhatsApp", true), waTestCases) - twaChannel := courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TWA", "+12065551212", "US", + twaChannel := test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TWA", "+12065551212", "US", map[string]interface{}{ configAccountSID: "accountSID", courier.ConfigAuthToken: "6789", @@ -283,7 +284,7 @@ func BenchmarkHandler(b *testing.B) { // setSendURL takes care of setting the send_url to our test server host func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { if c.ChannelType().String() == "TW" || c.ChannelType().String() == "SW" { - c.(*courier.MockChannel).SetConfig("send_url", s.URL) + c.(*test.MockChannel).SetConfig("send_url", s.URL) } else { twilioBaseURL = s.URL } @@ -645,25 +646,25 @@ var twaSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "T", "2020", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "T", "2020", "US", map[string]interface{}{ configAccountSID: "accountSID", courier.ConfigAuthToken: "authToken"}) - var tmsDefaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56cd", "TMS", "2021", "US", + var tmsDefaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56cd", "TMS", "2021", "US", map[string]interface{}{ configMessagingServiceSID: "messageServiceSID", configAccountSID: "accountSID", courier.ConfigAuthToken: "authToken"}) - var twDefaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TW", "2020", "US", + var twDefaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TW", "2020", "US", map[string]interface{}{ configAccountSID: "accountSID", courier.ConfigAuthToken: "authToken", configSendURL: "SEND_URL", }) - var swChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SW", "2020", "US", + var swChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SW", "2020", "US", map[string]interface{}{ configAccountSID: "accountSID", courier.ConfigAuthToken: "authToken", @@ -675,7 +676,7 @@ func TestSending(t *testing.T) { RunChannelSendTestCases(t, twDefaultChannel, newTWIMLHandler("TW", "TwiML", true), twDefaultSendTestCases, nil) RunChannelSendTestCases(t, swChannel, newTWIMLHandler("SW", "SignalWire", false), swSendTestCases, nil) - waChannel := courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SW", "+12065551212", "US", + waChannel := test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SW", "+12065551212", "US", map[string]interface{}{ configAccountSID: "accountSID", courier.ConfigAuthToken: "authToken", @@ -685,7 +686,7 @@ func TestSending(t *testing.T) { RunChannelSendTestCases(t, waChannel, newTWIMLHandler("T", "Twilio Whatsapp", true), waSendTestCases, nil) - twaChannel := courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TWA", "+12065551212", "US", + twaChannel := test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TWA", "+12065551212", "US", map[string]interface{}{ configAccountSID: "accountSID", courier.ConfigAuthToken: "authToken", diff --git a/handlers/twitter/twitter_test.go b/handlers/twitter/twitter_test.go index 6b27593a0..a58854a02 100644 --- a/handlers/twitter/twitter_test.go +++ b/handlers/twitter/twitter_test.go @@ -11,10 +11,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "TWT", "tweeter", "", + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "TWT", "tweeter", "", map[string]interface{}{ configHandleID: "835740314006511618", configAPIKey: "apiKey", diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index ca6b313a8..a8719ecde 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -12,6 +12,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) // setSend takes care of setting the sendURL to call @@ -181,14 +182,14 @@ func TestSending(t *testing.T) { maxMsgLength = 160 descriptionMaxLength = 10 - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "VP", "2020", "", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "VP", "2020", "", map[string]interface{}{ courier.ConfigAuthToken: "Token", }) - var invalidTokenChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "VP", "2020", "", + var invalidTokenChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "VP", "2020", "", map[string]interface{}{}, ) - var buttonLayoutChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "VP", "2021", "", + var buttonLayoutChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "VP", "2021", "", map[string]interface{}{ courier.ConfigAuthToken: "Token", "button_layout": map[string]interface{}{"bg_color": "#f7bb3f", "text": "*

", "text_size": "large"}, @@ -199,13 +200,13 @@ func TestSending(t *testing.T) { } var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "VP", "2020", "", map[string]interface{}{ + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "VP", "2020", "", map[string]interface{}{ courier.ConfigAuthToken: "Token", }), } var testChannelsWithWelcomeMessage = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "VP", "2020", "", map[string]interface{}{ + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "VP", "2020", "", map[string]interface{}{ courier.ConfigAuthToken: "Token", configViberWelcomeMessage: "Welcome to VP, Please subscribe here for more.", }), diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index 9fe47a993..f9ea385c4 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -14,6 +14,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) const ( @@ -22,7 +23,7 @@ const ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel( + test.NewMockChannel( channelUUID, "VK", "123456789", diff --git a/handlers/wavy/wavy_test.go b/handlers/wavy/wavy_test.go index f7fa44d08..0d061dcd8 100644 --- a/handlers/wavy/wavy_test.go +++ b/handlers/wavy/wavy_test.go @@ -7,10 +7,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WV", "2020", "BR", nil), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WV", "2020", "BR", nil), } var ( @@ -129,7 +130,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WV", "2020", "BR", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WV", "2020", "BR", map[string]interface{}{ courier.ConfigUsername: "user1", courier.ConfigAuthToken: "token", diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index 656efdd00..e684b4ec9 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -16,6 +16,7 @@ import ( "time" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/urns" "github.com/sirupsen/logrus" @@ -26,7 +27,7 @@ import ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WC", "2020", "US", + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WC", "2020", "US", map[string]interface{}{courier.ConfigSecret: "secret", configAppSecret: "app-secret", configAppID: "app-id"}), } @@ -254,7 +255,7 @@ func TestDescribe(t *testing.T) { WCAPI := buildMockWCAPI(testCases) defer WCAPI.Close() - mb := courier.NewMockBackend() + mb := test.NewMockBackend() conn := mb.RedisPool().Get() _, err := conn.Do("SET", "wechat_channel_access_token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ACCESS_TOKEN") @@ -283,7 +284,7 @@ func TestDescribe(t *testing.T) { } func TestBuildMediaRequest(t *testing.T) { - mb := courier.NewMockBackend() + mb := test.NewMockBackend() conn := mb.RedisPool().Get() _, err := conn.Do("SET", "wechat_channel_access_token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ACCESS_TOKEN") @@ -363,7 +364,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL}, } -func setupBackend(mb *courier.MockBackend) { +func setupBackend(mb *test.MockBackend) { conn := mb.RedisPool().Get() _, err := conn.Do("SET", "wechat_channel_access_token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ACCESS_TOKEN") @@ -376,6 +377,6 @@ func setupBackend(mb *courier.MockBackend) { func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WC", "2020", "US", map[string]interface{}{configAppSecret: "secret", configAppID: "app-id"}) + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WC", "2020", "US", map[string]interface{}{configAppSecret: "secret", configAppID: "app-id"}) RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, setupBackend) } diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index 1a35a0229..cd4658afe 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -11,11 +11,12 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" "github.com/stretchr/testify/assert" ) var testChannels = []courier.Channel{ - courier.NewMockChannel( + test.NewMockChannel( "8eb23e93-5ecb-45ba-b726-3b064e0c568c", "WA", "250788383383", @@ -24,7 +25,7 @@ var testChannels = []courier.Channel{ "auth_token": "the-auth-token", "base_url": "https://foo.bar/", }), - courier.NewMockChannel( + test.NewMockChannel( "8eb23e93-5ecb-45ba-b726-3b064e0c568c", "D3", "250788383383", @@ -33,7 +34,7 @@ var testChannels = []courier.Channel{ "auth_token": "the-auth-token", "base_url": "https://foo.bar/", }), - courier.NewMockChannel( + test.NewMockChannel( "8eb23e93-5ecb-45ba-b726-3b064e0c568c", "TXW", "250788383383", @@ -324,7 +325,7 @@ var waTestCases = []ChannelHandleTestCase{ } func TestBuildMediaRequest(t *testing.T) { - mb := courier.NewMockBackend() + mb := test.NewMockBackend() waHandler := &handler{NewBaseHandler(courier.ChannelType("WA"), "WhatsApp")} req, _ := waHandler.BuildDownloadMediaRequest(context.Background(), mb, testChannels[0], "https://example.org/v1/media/41") @@ -366,7 +367,7 @@ func BenchmarkHandler(b *testing.B) { // setSendURL takes care of setting the base_url to our test server host func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { retryParam = "retry" - c.(*courier.MockChannel).SetConfig("base_url", s.URL) + c.(*test.MockChannel).SetConfig("base_url", s.URL) } var defaultSendTestCases = []ChannelSendTestCase{ @@ -993,7 +994,7 @@ func mockAttachmentURLs(mediaServer *httptest.Server, testCases []ChannelSendTes } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WA", "250788383383", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WA", "250788383383", "US", map[string]interface{}{ "auth_token": "token123", "base_url": "https://foo.bar/", @@ -1001,7 +1002,7 @@ func TestSending(t *testing.T) { "version": "v2.35.2", }) - var hsmSupportChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WA", "250788383383", "US", + var hsmSupportChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WA", "250788383383", "US", map[string]interface{}{ "auth_token": "token123", "base_url": "https://foo.bar/", @@ -1010,7 +1011,7 @@ func TestSending(t *testing.T) { "version": "v2.35.2", }) - var d3Channel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "D3", "250788383383", "US", + var d3Channel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "D3", "250788383383", "US", map[string]interface{}{ "auth_token": "token123", "base_url": "https://foo.bar/", @@ -1018,7 +1019,7 @@ func TestSending(t *testing.T) { "version": "v2.35.2", }) - var txwChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TXW", "250788383383", "US", + var txwChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TXW", "250788383383", "US", map[string]interface{}{ "auth_token": "token123", "base_url": "https://foo.bar/", diff --git a/handlers/yo/yo_test.go b/handlers/yo/yo_test.go index 693d8e607..9a4dd0ea0 100644 --- a/handlers/yo/yo_test.go +++ b/handlers/yo/yo_test.go @@ -7,6 +7,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var ( @@ -21,7 +22,7 @@ var ( ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "YO", "2020", "US", map[string]interface{}{"username": "yo-username", "password": "yo-password"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "YO", "2020", "US", map[string]interface{}{"username": "yo-username", "password": "yo-password"}), } var handleTestCases = []ChannelHandleTestCase{ @@ -98,7 +99,7 @@ var getSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - var getChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "YO", "2020", "US", map[string]interface{}{"username": "yo-username", "password": "yo-password"}) + var getChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "YO", "2020", "US", map[string]interface{}{"username": "yo-username", "password": "yo-password"}) RunChannelSendTestCases(t, getChannel, newHandler(), getSendTestCases, nil) } diff --git a/handlers/zenvia/zenvia_test.go b/handlers/zenvia/zenvia_test.go index 2ef9db8b4..e57f54f86 100644 --- a/handlers/zenvia/zenvia_test.go +++ b/handlers/zenvia/zenvia_test.go @@ -7,15 +7,16 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testWhatsappChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZVW", "2020", "BR", map[string]interface{}{"api_key": "zv-api-token"}), - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZVS", "2020", "BR", map[string]interface{}{"api_key": "zv-api-token"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZVW", "2020", "BR", map[string]interface{}{"api_key": "zv-api-token"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZVS", "2020", "BR", map[string]interface{}{"api_key": "zv-api-token"}), } var testSMSChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZVS", "2020", "BR", map[string]interface{}{"api_key": "zv-api-token"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZVS", "2020", "BR", map[string]interface{}{"api_key": "zv-api-token"}), } var ( @@ -388,9 +389,9 @@ var defaultSMSSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultWhatsappChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZVW", "2020", "BR", map[string]interface{}{"api_key": "zv-api-token"}) + var defaultWhatsappChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZVW", "2020", "BR", map[string]interface{}{"api_key": "zv-api-token"}) RunChannelSendTestCases(t, defaultWhatsappChannel, newHandler("ZVW", "Zenvia WhatsApp"), defaultWhatsappSendTestCases, nil) - var defaultSMSChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZVS", "2020", "BR", map[string]interface{}{"api_key": "zv-api-token"}) + var defaultSMSChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZVS", "2020", "BR", map[string]interface{}{"api_key": "zv-api-token"}) RunChannelSendTestCases(t, defaultSMSChannel, newHandler("ZVS", "Zenvia SMS"), defaultSMSSendTestCases, nil) } diff --git a/handlers/zenviaold/zenviaold_test.go b/handlers/zenviaold/zenviaold_test.go index b7886d682..7541ba815 100644 --- a/handlers/zenviaold/zenviaold_test.go +++ b/handlers/zenviaold/zenviaold_test.go @@ -7,10 +7,11 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZV", "2020", "BR", map[string]interface{}{"username": "zv-username", "password": "zv-password"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZV", "2020", "BR", map[string]interface{}{"username": "zv-username", "password": "zv-password"}), } var ( @@ -203,6 +204,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZV", "2020", "BR", map[string]interface{}{"username": "zv-username", "password": "zv-password"}) + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZV", "2020", "BR", map[string]interface{}{"username": "zv-username", "password": "zv-password"}) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) } diff --git a/server_test.go b/server_test.go index cba8f1b4a..ffe315ef5 100644 --- a/server_test.go +++ b/server_test.go @@ -1,10 +1,12 @@ -package courier +package courier_test import ( "net/http" "testing" "time" + "github.com/nyaruka/courier" + "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/httpx" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" @@ -12,11 +14,11 @@ import ( func TestServer(t *testing.T) { logger := logrus.New() - config := NewConfig() + config := courier.NewConfig() config.StatusUsername = "admin" config.StatusPassword = "password123" - server := NewServerWithLogger(config, NewMockBackend(), logger) + server := courier.NewServerWithLogger(config, test.NewMockBackend(), logger) server.Start() defer server.Stop() @@ -79,7 +81,7 @@ func TestSanitizeBody(t *testing.T) { } for _, tc := range tcs { - result := sanitizeBody(tc.Body) + result := courier.SanitizeBody(tc.Body) assert.Equal(t, tc.Result, result, "%s: unexpected result", tc.Label) } } diff --git a/test.go b/test.go deleted file mode 100644 index 15f6cf555..000000000 --- a/test.go +++ /dev/null @@ -1,791 +0,0 @@ -package courier - -import ( - "context" - "encoding/json" - "fmt" - "log" - "os" - "strconv" - "strings" - "sync" - "time" - - "github.com/nyaruka/gocommon/urns" - "github.com/nyaruka/gocommon/uuids" - - "github.com/gomodule/redigo/redis" - _ "github.com/lib/pq" // postgres driver - "github.com/pkg/errors" -) - -//----------------------------------------------------------------------------- -// Mock backend implementation -//----------------------------------------------------------------------------- - -// MockBackend is a mocked version of a backend which doesn't require a real database or cache -type MockBackend struct { - channels map[ChannelUUID]Channel - channelsByAddress map[ChannelAddress]Channel - contacts map[urns.URN]Contact - media map[string]Media // url -> Media - queueMsgs []Msg - errorOnQueue bool - - mutex sync.RWMutex - outgoingMsgs []Msg - msgStatuses []MsgStatus - channelEvents []ChannelEvent - channelLogs []*ChannelLog - lastContactName string - - sentMsgs map[MsgID]bool - redisPool *redis.Pool - - seenExternalIDs []string -} - -// NewMockBackend returns a new mock backend suitable for testing -func NewMockBackend() *MockBackend { - redisPool := &redis.Pool{ - Wait: true, // makes callers wait for a connection - MaxActive: 5, // only open this many concurrent connections at once - MaxIdle: 2, // only keep up to 2 idle - IdleTimeout: 240 * time.Second, // how long to wait before reaping a connection - Dial: func() (redis.Conn, error) { - conn, err := redis.Dial("tcp", "localhost:6379") - if err != nil { - return nil, err - } - _, err = conn.Do("SELECT", 0) - return conn, err - }, - } - conn := redisPool.Get() - defer conn.Close() - - _, err := conn.Do("FLUSHDB") - if err != nil { - log.Fatal(err) - } - - return &MockBackend{ - channels: make(map[ChannelUUID]Channel), - channelsByAddress: make(map[ChannelAddress]Channel), - contacts: make(map[urns.URN]Contact), - media: make(map[string]Media), - sentMsgs: make(map[MsgID]bool), - redisPool: redisPool, - } -} - -// GetLastQueueMsg returns the last message queued to the server -func (mb *MockBackend) GetLastQueueMsg() (Msg, error) { - if len(mb.queueMsgs) == 0 { - return nil, ErrMsgNotFound - } - return mb.queueMsgs[len(mb.queueMsgs)-1], nil -} - -// GetLastChannelEvent returns the last event written to the server -func (mb *MockBackend) GetLastChannelEvent() (ChannelEvent, error) { - if len(mb.channelEvents) == 0 { - return nil, errors.New("no channel events") - } - return mb.channelEvents[len(mb.channelEvents)-1], nil -} - -// GetLastChannelLog returns the last channel log written to the server -func (mb *MockBackend) GetLastChannelLog() (*ChannelLog, error) { - if len(mb.channelLogs) == 0 { - return nil, errors.New("no channel logs") - } - return mb.channelLogs[len(mb.channelLogs)-1], nil -} - -// GetLastMsgStatus returns the last status written to the server -func (mb *MockBackend) GetLastMsgStatus() (MsgStatus, error) { - if len(mb.msgStatuses) == 0 { - return nil, errors.New("no msg statuses") - } - return mb.msgStatuses[len(mb.msgStatuses)-1], nil -} - -// GetLastContactName returns the contact name set on the last msg or channel event written -func (mb *MockBackend) GetLastContactName() string { - return mb.lastContactName -} - -// MockMedia adds the given media to the mocked backend -func (mb *MockBackend) MockMedia(media Media) { - mb.media[media.URL()] = media -} - -// DeleteMsgWithExternalID delete a message we receive an event that it should be deleted -func (mb *MockBackend) DeleteMsgWithExternalID(ctx context.Context, channel Channel, externalID string) error { - return nil -} - -// NewIncomingMsg creates a new message from the given params -func (mb *MockBackend) NewIncomingMsg(channel Channel, urn urns.URN, text string) Msg { - return &mockMsg{channel: channel, urn: urn, text: text} -} - -// NewOutgoingMsg creates a new outgoing message from the given params -func (mb *MockBackend) NewOutgoingMsg(channel Channel, id MsgID, urn urns.URN, text string, highPriority bool, quickReplies []string, topic string, responseToExternalID string) Msg { - return &mockMsg{channel: channel, id: id, urn: urn, text: text, highPriority: highPriority, quickReplies: quickReplies, topic: topic, responseToExternalID: responseToExternalID} -} - -// PushOutgoingMsg is a test method to add a message to our queue of messages to send -func (mb *MockBackend) PushOutgoingMsg(msg Msg) { - mb.mutex.Lock() - defer mb.mutex.Unlock() - - mb.outgoingMsgs = append(mb.outgoingMsgs, msg) -} - -// PopNextOutgoingMsg returns the next message that should be sent, or nil if there are none to send -func (mb *MockBackend) PopNextOutgoingMsg(ctx context.Context) (Msg, error) { - mb.mutex.Lock() - defer mb.mutex.Unlock() - - if len(mb.outgoingMsgs) > 0 { - msg, rest := mb.outgoingMsgs[0], mb.outgoingMsgs[1:] - mb.outgoingMsgs = rest - return msg, nil - } - - return nil, nil -} - -// WasMsgSent returns whether the passed in msg was already sent -func (mb *MockBackend) WasMsgSent(ctx context.Context, id MsgID) (bool, error) { - mb.mutex.Lock() - defer mb.mutex.Unlock() - - return mb.sentMsgs[id], nil -} - -func (mb *MockBackend) ClearMsgSent(ctx context.Context, id MsgID) error { - mb.mutex.Lock() - defer mb.mutex.Unlock() - - delete(mb.sentMsgs, id) - return nil -} - -// MarkOutgoingMsgComplete marks the passed msg as having been dealt with -func (mb *MockBackend) MarkOutgoingMsgComplete(ctx context.Context, msg Msg, s MsgStatus) { - mb.mutex.Lock() - defer mb.mutex.Unlock() - - mb.sentMsgs[msg.ID()] = true -} - -// WriteChannelLogs writes the passed in channel logs to the DB -func (mb *MockBackend) WriteChannelLogs(ctx context.Context, logs []*ChannelLog) error { - mb.mutex.Lock() - defer mb.mutex.Unlock() - - for _, log := range logs { - mb.channelLogs = append(mb.channelLogs, log) - } - return nil -} - -// SetErrorOnQueue is a mock method which makes the QueueMsg call throw the passed in error on next call -func (mb *MockBackend) SetErrorOnQueue(shouldError bool) { - mb.errorOnQueue = shouldError -} - -// WriteMsg queues the passed in message internally -func (mb *MockBackend) WriteMsg(ctx context.Context, m Msg) error { - mock := m.(*mockMsg) - - // this msg has already been written (we received it twice), we are a no op - if mock.alreadyWritten { - return nil - } - - if mb.errorOnQueue { - return errors.New("unable to queue message") - } - - mb.queueMsgs = append(mb.queueMsgs, m) - mb.lastContactName = m.(*mockMsg).contactName - return nil -} - -// NewMsgStatusForID creates a new Status object for the given message id -func (mb *MockBackend) NewMsgStatusForID(channel Channel, id MsgID, status MsgStatusValue) MsgStatus { - return &mockMsgStatus{ - channel: channel, - id: id, - status: status, - createdOn: time.Now().In(time.UTC), - } -} - -// NewMsgStatusForExternalID creates a new Status object for the given external id -func (mb *MockBackend) NewMsgStatusForExternalID(channel Channel, externalID string, status MsgStatusValue) MsgStatus { - return &mockMsgStatus{ - channel: channel, - externalID: externalID, - status: status, - createdOn: time.Now().In(time.UTC), - } -} - -// WriteMsgStatus writes the status update to our queue -func (mb *MockBackend) WriteMsgStatus(ctx context.Context, status MsgStatus) error { - mb.mutex.Lock() - defer mb.mutex.Unlock() - - mb.msgStatuses = append(mb.msgStatuses, status) - return nil -} - -// NewChannelEvent creates a new channel event with the passed in parameters -func (mb *MockBackend) NewChannelEvent(channel Channel, eventType ChannelEventType, urn urns.URN) ChannelEvent { - return &mockChannelEvent{ - channel: channel, - eventType: eventType, - urn: urn, - } -} - -// WriteChannelEvent writes the channel event passed in -func (mb *MockBackend) WriteChannelEvent(ctx context.Context, event ChannelEvent) error { - mb.mutex.Lock() - defer mb.mutex.Unlock() - - mb.channelEvents = append(mb.channelEvents, event) - mb.lastContactName = event.(*mockChannelEvent).contactName - return nil -} - -// GetChannel returns the channel with the passed in type and channel uuid -func (mb *MockBackend) GetChannel(ctx context.Context, cType ChannelType, uuid ChannelUUID) (Channel, error) { - channel, found := mb.channels[uuid] - if !found { - return nil, ErrChannelNotFound - } - return channel, nil -} - -// GetChannelByAddress returns the channel with the passed in type and channel address -func (mb *MockBackend) GetChannelByAddress(ctx context.Context, cType ChannelType, address ChannelAddress) (Channel, error) { - channel, found := mb.channelsByAddress[address] - if !found { - return nil, ErrChannelNotFound - } - return channel, nil -} - -// GetContact creates a new contact with the passed in channel and URN -func (mb *MockBackend) GetContact(ctx context.Context, channel Channel, urn urns.URN, auth string, name string) (Contact, error) { - contact, found := mb.contacts[urn] - if !found { - uuid, _ := NewContactUUID(string(uuids.New())) - contact = &mockContact{channel, urn, auth, uuid} - mb.contacts[urn] = contact - } - return contact, nil -} - -// AddURNtoContact adds a URN to the passed in contact -func (mb *MockBackend) AddURNtoContact(context context.Context, channel Channel, contact Contact, urn urns.URN) (urns.URN, error) { - mb.contacts[urn] = contact - return urn, nil -} - -// RemoveURNFromcontact removes a URN from the passed in contact -func (mb *MockBackend) RemoveURNfromContact(context context.Context, channel Channel, contact Contact, urn urns.URN) (urns.URN, error) { - contact, found := mb.contacts[urn] - if found { - delete(mb.contacts, urn) - } - return urn, nil -} - -// AddChannel adds a test channel to the test server -func (mb *MockBackend) AddChannel(channel Channel) { - mb.channels[channel.UUID()] = channel - mb.channelsByAddress[channel.ChannelAddress()] = channel -} - -// ClearChannels is a utility function on our mock server to clear all added channels -func (mb *MockBackend) ClearChannels() { - mb.channels = nil - mb.channelsByAddress = nil -} - -// Start starts our mock backend -func (mb *MockBackend) Start() error { return nil } - -// Stop stops our mock backend -func (mb *MockBackend) Stop() error { return nil } - -// Cleanup cleans up any connections that are open -func (mb *MockBackend) Cleanup() error { return nil } - -// ClearQueueMsgs clears our mock msg queue -func (mb *MockBackend) ClearQueueMsgs() { - mb.queueMsgs = nil -} - -// ClearSeenExternalIDs clears our mock seen external ids -func (mb *MockBackend) ClearSeenExternalIDs() { - mb.seenExternalIDs = nil -} - -// LenQueuedMsgs Get the length of queued msgs -func (mb *MockBackend) LenQueuedMsgs() int { - return len(mb.queueMsgs) -} - -// CheckExternalIDSeen checks if external ID has been seen in a period -func (mb *MockBackend) CheckExternalIDSeen(msg Msg) Msg { - m := msg.(*mockMsg) - - for _, b := range mb.seenExternalIDs { - if b == msg.ExternalID() { - m.alreadyWritten = true - return m - } - } - return m -} - -// WriteExternalIDSeen marks a external ID as seen for a period -func (mb *MockBackend) WriteExternalIDSeen(msg Msg) { - mb.seenExternalIDs = append(mb.seenExternalIDs, msg.ExternalID()) -} - -// ResolveMedia resolves the passed in media URL to a media object -func (mb *MockBackend) ResolveMedia(ctx context.Context, mediaUrl string) (Media, error) { - media := mb.media[mediaUrl] - if media == nil { - return nil, nil - } - - return media, nil -} - -// Health gives a string representing our health, empty for our mock -func (mb *MockBackend) Health() string { - return "" -} - -// Status returns a string describing the status of the service, queue size etc.. -func (mb *MockBackend) Status() string { - return "" -} - -// Heartbeat is a noop for our mock backend -func (mb *MockBackend) Heartbeat() error { - return nil -} - -// RedisPool returns the redisPool for this backend -func (mb *MockBackend) RedisPool() *redis.Pool { - return mb.redisPool -} - -func buildMockBackend(config *Config) Backend { - return NewMockBackend() -} - -func init() { - RegisterBackend("mock", buildMockBackend) -} - -//----------------------------------------------------------------------------- -// Mock channel implementation -//----------------------------------------------------------------------------- - -// MockChannel implements the Channel interface and is used in our tests -type MockChannel struct { - uuid ChannelUUID - channelType ChannelType - schemes []string - address ChannelAddress - country string - role string - config map[string]interface{} - orgConfig map[string]interface{} -} - -// UUID returns the uuid for this channel -func (c *MockChannel) UUID() ChannelUUID { return c.uuid } - -// Name returns the name of this channel, we just return our UUID for our mock instances -func (c *MockChannel) Name() string { return fmt.Sprintf("Channel: %s", c.uuid.String()) } - -// ChannelType returns the type of this channel -func (c *MockChannel) ChannelType() ChannelType { return c.channelType } - -// SetScheme sets the scheme for this channel -func (c *MockChannel) SetScheme(scheme string) { c.schemes = []string{scheme} } - -// Schemes returns the schemes for this channel -func (c *MockChannel) Schemes() []string { return c.schemes } - -// IsScheme returns whether the passed in scheme is the scheme for this channel -func (c *MockChannel) IsScheme(scheme string) bool { - return len(c.schemes) == 1 && c.schemes[0] == scheme -} - -// Address returns the address as a string of this channel -func (c *MockChannel) Address() string { return c.address.String() } - -// ChannelAddress returns the address of this channel -func (c *MockChannel) ChannelAddress() ChannelAddress { return c.address } - -// Country returns the country this channel is for (if any) -func (c *MockChannel) Country() string { return c.country } - -// SetConfig sets the passed in config parameter -func (c *MockChannel) SetConfig(key string, value interface{}) { - c.config[key] = value -} - -// CallbackDomain returns the callback domain to use for this channel -func (c *MockChannel) CallbackDomain(fallbackDomain string) string { - value, found := c.config[ConfigCallbackDomain] - if !found { - return fallbackDomain - } - return value.(string) -} - -// ConfigForKey returns the config value for the passed in key -func (c *MockChannel) ConfigForKey(key string, defaultValue interface{}) interface{} { - value, found := c.config[key] - if !found { - return defaultValue - } - return value -} - -// StringConfigForKey returns the config value for the passed in key -func (c *MockChannel) StringConfigForKey(key string, defaultValue string) string { - val := c.ConfigForKey(key, defaultValue) - str, isStr := val.(string) - if !isStr { - return defaultValue - } - return str -} - -// BoolConfigForKey returns the config value for the passed in key -func (c *MockChannel) BoolConfigForKey(key string, defaultValue bool) bool { - val := c.ConfigForKey(key, defaultValue) - b, isBool := val.(bool) - if !isBool { - return defaultValue - } - return b -} - -// IntConfigForKey returns the config value for the passed in key -func (c *MockChannel) IntConfigForKey(key string, defaultValue int) int { - val := c.ConfigForKey(key, defaultValue) - - // golang unmarshals number literals in JSON into float64s by default - f, isFloat := val.(float64) - if isFloat { - return int(f) - } - - // test authors may use literal ints - i, isInt := val.(int) - if isInt { - return i - } - - str, isStr := val.(string) - if isStr { - i, err := strconv.Atoi(str) - if err == nil { - return i - } - } - return defaultValue -} - -// OrgConfigForKey returns the org config value for the passed in key -func (c *MockChannel) OrgConfigForKey(key string, defaultValue interface{}) interface{} { - value, found := c.orgConfig[key] - if !found { - return defaultValue - } - return value -} - -// SetRoles sets the role on the channel -func (c *MockChannel) SetRoles(roles []ChannelRole) { - c.role = fmt.Sprint(roles) -} - -// Roles returns the roles of this channel -func (c *MockChannel) Roles() []ChannelRole { - roles := []ChannelRole{} - for _, char := range strings.Split(c.role, "") { - roles = append(roles, ChannelRole(char)) - } - return roles -} - -// HasRole returns whether the passed in channel supports the passed role -func (c *MockChannel) HasRole(role ChannelRole) bool { - for _, r := range c.Roles() { - if r == role { - return true - } - } - return false -} - -// NewMockChannel creates a new mock channel for the passed in type, address, country and config -func NewMockChannel(uuid string, channelType string, address string, country string, config map[string]interface{}) *MockChannel { - cUUID, _ := NewChannelUUID(uuid) - - channel := &MockChannel{ - uuid: cUUID, - channelType: ChannelType(channelType), - schemes: []string{urns.TelScheme}, - address: ChannelAddress(address), - country: country, - config: config, - role: "SR", - orgConfig: map[string]interface{}{}, - } - return channel -} - -//----------------------------------------------------------------------------- -// Mock msg implementation -//----------------------------------------------------------------------------- - -type mockMsg struct { - channel Channel - id MsgID - uuid MsgUUID - text string - attachments []string - externalID string - urn urns.URN - urnAuth string - contactName string - highPriority bool - quickReplies []string - topic string - responseToExternalID string - metadata json.RawMessage - alreadyWritten bool - isResend bool - - flow *FlowReference - - receivedOn *time.Time - sentOn *time.Time - wiredOn *time.Time -} - -func (m *mockMsg) SessionStatus() string { return "" } - -func (m *mockMsg) Flow() *FlowReference { return m.flow } - -func (m *mockMsg) FlowName() string { - if m.flow == nil { - return "" - } - return m.flow.Name -} - -func (m *mockMsg) FlowUUID() string { - if m.flow == nil { - return "" - } - return m.flow.UUID -} - -func (m *mockMsg) Channel() Channel { return m.channel } -func (m *mockMsg) ID() MsgID { return m.id } -func (m *mockMsg) EventID() int64 { return int64(m.id) } -func (m *mockMsg) UUID() MsgUUID { return m.uuid } -func (m *mockMsg) Text() string { return m.text } -func (m *mockMsg) Attachments() []string { return m.attachments } -func (m *mockMsg) ExternalID() string { return m.externalID } -func (m *mockMsg) URN() urns.URN { return m.urn } -func (m *mockMsg) URNAuth() string { return m.urnAuth } -func (m *mockMsg) ContactName() string { return m.contactName } -func (m *mockMsg) HighPriority() bool { return m.highPriority } -func (m *mockMsg) QuickReplies() []string { return m.quickReplies } -func (m *mockMsg) Topic() string { return m.topic } -func (m *mockMsg) ResponseToExternalID() string { return m.responseToExternalID } -func (m *mockMsg) Metadata() json.RawMessage { return m.metadata } -func (m *mockMsg) IsResend() bool { return m.isResend } - -func (m *mockMsg) ReceivedOn() *time.Time { return m.receivedOn } -func (m *mockMsg) SentOn() *time.Time { return m.sentOn } -func (m *mockMsg) WiredOn() *time.Time { return m.wiredOn } - -func (m *mockMsg) WithContactName(name string) Msg { m.contactName = name; return m } -func (m *mockMsg) WithURNAuth(auth string) Msg { m.urnAuth = auth; return m } -func (m *mockMsg) WithReceivedOn(date time.Time) Msg { m.receivedOn = &date; return m } -func (m *mockMsg) WithExternalID(id string) Msg { m.externalID = id; return m } -func (m *mockMsg) WithID(id MsgID) Msg { m.id = id; return m } -func (m *mockMsg) WithUUID(uuid MsgUUID) Msg { m.uuid = uuid; return m } -func (m *mockMsg) WithAttachment(url string) Msg { - m.attachments = append(m.attachments, url) - return m -} -func (m *mockMsg) WithMetadata(metadata json.RawMessage) Msg { m.metadata = metadata; return m } - -func (m *mockMsg) WithFlow(flow *FlowReference) Msg { m.flow = flow; return m } - -//----------------------------------------------------------------------------- -// Mock status implementation -//----------------------------------------------------------------------------- - -type mockMsgStatus struct { - channel Channel - id MsgID - oldURN urns.URN - newURN urns.URN - externalID string - status MsgStatusValue - createdOn time.Time - - logs []*ChannelLog -} - -func (m *mockMsgStatus) ChannelUUID() ChannelUUID { return m.channel.UUID() } -func (m *mockMsgStatus) ID() MsgID { return m.id } -func (m *mockMsgStatus) EventID() int64 { return int64(m.id) } - -func (m *mockMsgStatus) SetUpdatedURN(old, new urns.URN) error { - m.oldURN = old - m.newURN = new - return nil -} -func (m *mockMsgStatus) UpdatedURN() (urns.URN, urns.URN) { - return m.oldURN, m.newURN -} -func (m *mockMsgStatus) HasUpdatedURN() bool { - if m.oldURN != urns.NilURN && m.newURN != urns.NilURN { - return true - } - return false -} - -func (m *mockMsgStatus) ExternalID() string { return m.externalID } -func (m *mockMsgStatus) SetExternalID(id string) { m.externalID = id } - -func (m *mockMsgStatus) Status() MsgStatusValue { return m.status } -func (m *mockMsgStatus) SetStatus(status MsgStatusValue) { m.status = status } - -func (m *mockMsgStatus) Logs() []*ChannelLog { return m.logs } -func (m *mockMsgStatus) AddLog(log *ChannelLog) { m.logs = append(m.logs, log) } - -//----------------------------------------------------------------------------- -// Mock channel event implementation -//----------------------------------------------------------------------------- - -type mockChannelEvent struct { - channel Channel - eventType ChannelEventType - urn urns.URN - createdOn time.Time - occurredOn time.Time - - contactName string - extra map[string]interface{} - - logs []*ChannelLog -} - -func (e *mockChannelEvent) EventID() int64 { return 0 } -func (e *mockChannelEvent) ChannelUUID() ChannelUUID { return e.channel.UUID() } -func (e *mockChannelEvent) EventType() ChannelEventType { return e.eventType } -func (e *mockChannelEvent) CreatedOn() time.Time { return e.createdOn } -func (e *mockChannelEvent) OccurredOn() time.Time { return e.occurredOn } -func (e *mockChannelEvent) Extra() map[string]interface{} { return e.extra } -func (e *mockChannelEvent) ContactName() string { return e.contactName } -func (e *mockChannelEvent) URN() urns.URN { return e.urn } - -func (e *mockChannelEvent) WithExtra(extra map[string]interface{}) ChannelEvent { - e.extra = extra - return e -} -func (e *mockChannelEvent) WithContactName(name string) ChannelEvent { - e.contactName = name - return e -} -func (e *mockChannelEvent) WithOccurredOn(time time.Time) ChannelEvent { - e.occurredOn = time - return e -} - -func (e *mockChannelEvent) Logs() []*ChannelLog { return e.logs } -func (e *mockChannelEvent) AddLog(log *ChannelLog) { e.logs = append(e.logs, log) } - -//----------------------------------------------------------------------------- -// Mock Contact implementation -//----------------------------------------------------------------------------- - -type mockContact struct { - channel Channel - urn urns.URN - auth string - uuid ContactUUID -} - -func (c *mockContact) UUID() ContactUUID { return c.uuid } - -func ReadFile(path string) []byte { - d, err := os.ReadFile(path) - if err != nil { - panic(err) - } - return d -} - -//----------------------------------------------------------------------------- -// Mock media implementation -//----------------------------------------------------------------------------- - -type mockMedia struct { - name string - contentType string - url string - size int - width int - height int - duration int - alternates []Media -} - -func (m *mockMedia) Name() string { return m.name } -func (m *mockMedia) ContentType() string { return m.contentType } -func (m *mockMedia) URL() string { return m.url } -func (m *mockMedia) Size() int { return m.size } -func (m *mockMedia) Width() int { return m.width } -func (m *mockMedia) Height() int { return m.height } -func (m *mockMedia) Duration() int { return m.duration } -func (m *mockMedia) Alternates() []Media { return m.alternates } - -func NewMockMedia(name, contentType, url string, size, width, height, duration int, alternates []Media) Media { - return &mockMedia{ - name: name, - contentType: contentType, - url: url, - size: size, - width: width, - height: height, - duration: duration, - alternates: alternates, - } -} diff --git a/test/backend.go b/test/backend.go new file mode 100644 index 000000000..dd4b22290 --- /dev/null +++ b/test/backend.go @@ -0,0 +1,396 @@ +package test + +import ( + "context" + "log" + "sync" + "time" + + "github.com/nyaruka/courier" + "github.com/nyaruka/gocommon/urns" + "github.com/nyaruka/gocommon/uuids" + + "github.com/gomodule/redigo/redis" + _ "github.com/lib/pq" // postgres driver + "github.com/pkg/errors" +) + +func init() { + courier.RegisterBackend("mock", buildMockBackend) +} + +// MockBackend is a mocked version of a backend which doesn't require a real database or cache +type MockBackend struct { + channels map[courier.ChannelUUID]courier.Channel + channelsByAddress map[courier.ChannelAddress]courier.Channel + contacts map[urns.URN]courier.Contact + media map[string]courier.Media // url -> Media + queueMsgs []courier.Msg + errorOnQueue bool + + mutex sync.RWMutex + redisPool *redis.Pool + + outgoingMsgs []courier.Msg + msgStatuses []courier.MsgStatus + channelEvents []courier.ChannelEvent + channelLogs []*courier.ChannelLog + lastContactName string + sentMsgs map[courier.MsgID]bool + seenExternalIDs []string +} + +// NewMockBackend returns a new mock backend suitable for testing +func NewMockBackend() *MockBackend { + redisPool := &redis.Pool{ + Wait: true, // makes callers wait for a connection + MaxActive: 5, // only open this many concurrent connections at once + MaxIdle: 2, // only keep up to 2 idle + IdleTimeout: 240 * time.Second, // how long to wait before reaping a connection + Dial: func() (redis.Conn, error) { + conn, err := redis.Dial("tcp", "localhost:6379") + if err != nil { + return nil, err + } + _, err = conn.Do("SELECT", 0) + return conn, err + }, + } + conn := redisPool.Get() + defer conn.Close() + + _, err := conn.Do("FLUSHDB") + if err != nil { + log.Fatal(err) + } + + return &MockBackend{ + channels: make(map[courier.ChannelUUID]courier.Channel), + channelsByAddress: make(map[courier.ChannelAddress]courier.Channel), + contacts: make(map[urns.URN]courier.Contact), + media: make(map[string]courier.Media), + sentMsgs: make(map[courier.MsgID]bool), + redisPool: redisPool, + } +} + +func (mb *MockBackend) ChannelLogs() []*courier.ChannelLog { return mb.channelLogs } +func (mb *MockBackend) MsgStatuses() []courier.MsgStatus { return mb.msgStatuses } +func (mb *MockBackend) ClearMsgStatuses() { mb.msgStatuses = nil } + +// GetLastQueueMsg returns the last message queued to the server +func (mb *MockBackend) GetLastQueueMsg() (courier.Msg, error) { + if len(mb.queueMsgs) == 0 { + return nil, courier.ErrMsgNotFound + } + return mb.queueMsgs[len(mb.queueMsgs)-1], nil +} + +// GetLastChannelEvent returns the last event written to the server +func (mb *MockBackend) GetLastChannelEvent() (courier.ChannelEvent, error) { + if len(mb.channelEvents) == 0 { + return nil, errors.New("no channel events") + } + return mb.channelEvents[len(mb.channelEvents)-1], nil +} + +// GetLastChannelLog returns the last channel log written to the server +func (mb *MockBackend) GetLastChannelLog() (*courier.ChannelLog, error) { + if len(mb.channelLogs) == 0 { + return nil, errors.New("no channel logs") + } + return mb.channelLogs[len(mb.channelLogs)-1], nil +} + +// GetLastMsgStatus returns the last status written to the server +func (mb *MockBackend) GetLastMsgStatus() (courier.MsgStatus, error) { + if len(mb.msgStatuses) == 0 { + return nil, errors.New("no msg statuses") + } + return mb.msgStatuses[len(mb.msgStatuses)-1], nil +} + +// GetLastContactName returns the contact name set on the last msg or channel event written +func (mb *MockBackend) GetLastContactName() string { + return mb.lastContactName +} + +// MockMedia adds the given media to the mocked backend +func (mb *MockBackend) MockMedia(media courier.Media) { + mb.media[media.URL()] = media +} + +// DeleteMsgWithExternalID delete a message we receive an event that it should be deleted +func (mb *MockBackend) DeleteMsgWithExternalID(ctx context.Context, channel courier.Channel, externalID string) error { + return nil +} + +// NewIncomingMsg creates a new message from the given params +func (mb *MockBackend) NewIncomingMsg(channel courier.Channel, urn urns.URN, text string) courier.Msg { + return &mockMsg{channel: channel, urn: urn, text: text} +} + +// NewOutgoingMsg creates a new outgoing message from the given params +func (mb *MockBackend) NewOutgoingMsg(channel courier.Channel, id courier.MsgID, urn urns.URN, text string, highPriority bool, quickReplies []string, topic string, responseToExternalID string) courier.Msg { + return &mockMsg{channel: channel, id: id, urn: urn, text: text, highPriority: highPriority, quickReplies: quickReplies, topic: topic, responseToExternalID: responseToExternalID} +} + +// PushOutgoingMsg is a test method to add a message to our queue of messages to send +func (mb *MockBackend) PushOutgoingMsg(msg courier.Msg) { + mb.mutex.Lock() + defer mb.mutex.Unlock() + + mb.outgoingMsgs = append(mb.outgoingMsgs, msg) +} + +// PopNextOutgoingMsg returns the next message that should be sent, or nil if there are none to send +func (mb *MockBackend) PopNextOutgoingMsg(ctx context.Context) (courier.Msg, error) { + mb.mutex.Lock() + defer mb.mutex.Unlock() + + if len(mb.outgoingMsgs) > 0 { + msg, rest := mb.outgoingMsgs[0], mb.outgoingMsgs[1:] + mb.outgoingMsgs = rest + return msg, nil + } + + return nil, nil +} + +// WasMsgSent returns whether the passed in msg was already sent +func (mb *MockBackend) WasMsgSent(ctx context.Context, id courier.MsgID) (bool, error) { + mb.mutex.Lock() + defer mb.mutex.Unlock() + + return mb.sentMsgs[id], nil +} + +func (mb *MockBackend) ClearMsgSent(ctx context.Context, id courier.MsgID) error { + mb.mutex.Lock() + defer mb.mutex.Unlock() + + delete(mb.sentMsgs, id) + return nil +} + +// MarkOutgoingMsgComplete marks the passed msg as having been dealt with +func (mb *MockBackend) MarkOutgoingMsgComplete(ctx context.Context, msg courier.Msg, s courier.MsgStatus) { + mb.mutex.Lock() + defer mb.mutex.Unlock() + + mb.sentMsgs[msg.ID()] = true +} + +// WriteChannelLogs writes the passed in channel logs to the DB +func (mb *MockBackend) WriteChannelLogs(ctx context.Context, logs []*courier.ChannelLog) error { + mb.mutex.Lock() + defer mb.mutex.Unlock() + + for _, log := range logs { + mb.channelLogs = append(mb.channelLogs, log) + } + return nil +} + +// SetErrorOnQueue is a mock method which makes the QueueMsg call throw the passed in error on next call +func (mb *MockBackend) SetErrorOnQueue(shouldError bool) { + mb.errorOnQueue = shouldError +} + +// WriteMsg queues the passed in message internally +func (mb *MockBackend) WriteMsg(ctx context.Context, m courier.Msg) error { + mock := m.(*mockMsg) + + // this msg has already been written (we received it twice), we are a no op + if mock.alreadyWritten { + return nil + } + + if mb.errorOnQueue { + return errors.New("unable to queue message") + } + + mb.queueMsgs = append(mb.queueMsgs, m) + mb.lastContactName = m.(*mockMsg).contactName + return nil +} + +// NewMsgStatusForID creates a new Status object for the given message id +func (mb *MockBackend) NewMsgStatusForID(channel courier.Channel, id courier.MsgID, status courier.MsgStatusValue) courier.MsgStatus { + return &mockMsgStatus{ + channel: channel, + id: id, + status: status, + createdOn: time.Now().In(time.UTC), + } +} + +// NewMsgStatusForExternalID creates a new Status object for the given external id +func (mb *MockBackend) NewMsgStatusForExternalID(channel courier.Channel, externalID string, status courier.MsgStatusValue) courier.MsgStatus { + return &mockMsgStatus{ + channel: channel, + externalID: externalID, + status: status, + createdOn: time.Now().In(time.UTC), + } +} + +// WriteMsgStatus writes the status update to our queue +func (mb *MockBackend) WriteMsgStatus(ctx context.Context, status courier.MsgStatus) error { + mb.mutex.Lock() + defer mb.mutex.Unlock() + + mb.msgStatuses = append(mb.msgStatuses, status) + return nil +} + +// NewChannelEvent creates a new channel event with the passed in parameters +func (mb *MockBackend) NewChannelEvent(channel courier.Channel, eventType courier.ChannelEventType, urn urns.URN) courier.ChannelEvent { + return &mockChannelEvent{ + channel: channel, + eventType: eventType, + urn: urn, + } +} + +// WriteChannelEvent writes the channel event passed in +func (mb *MockBackend) WriteChannelEvent(ctx context.Context, event courier.ChannelEvent) error { + mb.mutex.Lock() + defer mb.mutex.Unlock() + + mb.channelEvents = append(mb.channelEvents, event) + mb.lastContactName = event.(*mockChannelEvent).contactName + return nil +} + +// GetChannel returns the channel with the passed in type and channel uuid +func (mb *MockBackend) GetChannel(ctx context.Context, cType courier.ChannelType, uuid courier.ChannelUUID) (courier.Channel, error) { + channel, found := mb.channels[uuid] + if !found { + return nil, courier.ErrChannelNotFound + } + return channel, nil +} + +// GetChannelByAddress returns the channel with the passed in type and channel address +func (mb *MockBackend) GetChannelByAddress(ctx context.Context, cType courier.ChannelType, address courier.ChannelAddress) (courier.Channel, error) { + channel, found := mb.channelsByAddress[address] + if !found { + return nil, courier.ErrChannelNotFound + } + return channel, nil +} + +// GetContact creates a new contact with the passed in channel and URN +func (mb *MockBackend) GetContact(ctx context.Context, channel courier.Channel, urn urns.URN, auth string, name string) (courier.Contact, error) { + contact, found := mb.contacts[urn] + if !found { + uuid, _ := courier.NewContactUUID(string(uuids.New())) + contact = &mockContact{channel, urn, auth, uuid} + mb.contacts[urn] = contact + } + return contact, nil +} + +// AddURNtoContact adds a URN to the passed in contact +func (mb *MockBackend) AddURNtoContact(context context.Context, channel courier.Channel, contact courier.Contact, urn urns.URN) (urns.URN, error) { + mb.contacts[urn] = contact + return urn, nil +} + +// RemoveURNFromcontact removes a URN from the passed in contact +func (mb *MockBackend) RemoveURNfromContact(context context.Context, channel courier.Channel, contact courier.Contact, urn urns.URN) (urns.URN, error) { + contact, found := mb.contacts[urn] + if found { + delete(mb.contacts, urn) + } + return urn, nil +} + +// AddChannel adds a test channel to the test server +func (mb *MockBackend) AddChannel(channel courier.Channel) { + mb.channels[channel.UUID()] = channel + mb.channelsByAddress[channel.ChannelAddress()] = channel +} + +// ClearChannels is a utility function on our mock server to clear all added channels +func (mb *MockBackend) ClearChannels() { + mb.channels = nil + mb.channelsByAddress = nil +} + +// Start starts our mock backend +func (mb *MockBackend) Start() error { return nil } + +// Stop stops our mock backend +func (mb *MockBackend) Stop() error { return nil } + +// Cleanup cleans up any connections that are open +func (mb *MockBackend) Cleanup() error { return nil } + +// ClearQueueMsgs clears our mock msg queue +func (mb *MockBackend) ClearQueueMsgs() { + mb.queueMsgs = nil +} + +// ClearSeenExternalIDs clears our mock seen external ids +func (mb *MockBackend) ClearSeenExternalIDs() { + mb.seenExternalIDs = nil +} + +// LenQueuedMsgs Get the length of queued msgs +func (mb *MockBackend) LenQueuedMsgs() int { + return len(mb.queueMsgs) +} + +// CheckExternalIDSeen checks if external ID has been seen in a period +func (mb *MockBackend) CheckExternalIDSeen(msg courier.Msg) courier.Msg { + m := msg.(*mockMsg) + + for _, b := range mb.seenExternalIDs { + if b == msg.ExternalID() { + m.alreadyWritten = true + return m + } + } + return m +} + +// WriteExternalIDSeen marks a external ID as seen for a period +func (mb *MockBackend) WriteExternalIDSeen(msg courier.Msg) { + mb.seenExternalIDs = append(mb.seenExternalIDs, msg.ExternalID()) +} + +// ResolveMedia resolves the passed in media URL to a media object +func (mb *MockBackend) ResolveMedia(ctx context.Context, mediaUrl string) (courier.Media, error) { + media := mb.media[mediaUrl] + if media == nil { + return nil, nil + } + + return media, nil +} + +// Health gives a string representing our health, empty for our mock +func (mb *MockBackend) Health() string { + return "" +} + +// Status returns a string describing the status of the service, queue size etc.. +func (mb *MockBackend) Status() string { + return "" +} + +// Heartbeat is a noop for our mock backend +func (mb *MockBackend) Heartbeat() error { + return nil +} + +// RedisPool returns the redisPool for this backend +func (mb *MockBackend) RedisPool() *redis.Pool { + return mb.redisPool +} + +func buildMockBackend(config *courier.Config) courier.Backend { + return NewMockBackend() +} diff --git a/test/channel.go b/test/channel.go new file mode 100644 index 000000000..65992559a --- /dev/null +++ b/test/channel.go @@ -0,0 +1,170 @@ +package test + +import ( + "fmt" + "strconv" + "strings" + + "github.com/nyaruka/courier" + "github.com/nyaruka/gocommon/urns" +) + +// MockChannel implements the Channel interface and is used in our tests +type MockChannel struct { + uuid courier.ChannelUUID + channelType courier.ChannelType + schemes []string + address courier.ChannelAddress + country string + role string + config map[string]interface{} + orgConfig map[string]interface{} +} + +// UUID returns the uuid for this channel +func (c *MockChannel) UUID() courier.ChannelUUID { return c.uuid } + +// Name returns the name of this channel, we just return our UUID for our mock instances +func (c *MockChannel) Name() string { return fmt.Sprintf("Channel: %s", c.uuid.String()) } + +// ChannelType returns the type of this channel +func (c *MockChannel) ChannelType() courier.ChannelType { return c.channelType } + +// SetScheme sets the scheme for this channel +func (c *MockChannel) SetScheme(scheme string) { c.schemes = []string{scheme} } + +// Schemes returns the schemes for this channel +func (c *MockChannel) Schemes() []string { return c.schemes } + +// IsScheme returns whether the passed in scheme is the scheme for this channel +func (c *MockChannel) IsScheme(scheme string) bool { + return len(c.schemes) == 1 && c.schemes[0] == scheme +} + +// Address returns the address as a string of this channel +func (c *MockChannel) Address() string { return c.address.String() } + +// ChannelAddress returns the address of this channel +func (c *MockChannel) ChannelAddress() courier.ChannelAddress { return c.address } + +// Country returns the country this channel is for (if any) +func (c *MockChannel) Country() string { return c.country } + +// SetConfig sets the passed in config parameter +func (c *MockChannel) SetConfig(key string, value interface{}) { + c.config[key] = value +} + +// CallbackDomain returns the callback domain to use for this channel +func (c *MockChannel) CallbackDomain(fallbackDomain string) string { + value, found := c.config[courier.ConfigCallbackDomain] + if !found { + return fallbackDomain + } + return value.(string) +} + +// ConfigForKey returns the config value for the passed in key +func (c *MockChannel) ConfigForKey(key string, defaultValue interface{}) interface{} { + value, found := c.config[key] + if !found { + return defaultValue + } + return value +} + +// StringConfigForKey returns the config value for the passed in key +func (c *MockChannel) StringConfigForKey(key string, defaultValue string) string { + val := c.ConfigForKey(key, defaultValue) + str, isStr := val.(string) + if !isStr { + return defaultValue + } + return str +} + +// BoolConfigForKey returns the config value for the passed in key +func (c *MockChannel) BoolConfigForKey(key string, defaultValue bool) bool { + val := c.ConfigForKey(key, defaultValue) + b, isBool := val.(bool) + if !isBool { + return defaultValue + } + return b +} + +// IntConfigForKey returns the config value for the passed in key +func (c *MockChannel) IntConfigForKey(key string, defaultValue int) int { + val := c.ConfigForKey(key, defaultValue) + + // golang unmarshals number literals in JSON into float64s by default + f, isFloat := val.(float64) + if isFloat { + return int(f) + } + + // test authors may use literal ints + i, isInt := val.(int) + if isInt { + return i + } + + str, isStr := val.(string) + if isStr { + i, err := strconv.Atoi(str) + if err == nil { + return i + } + } + return defaultValue +} + +// OrgConfigForKey returns the org config value for the passed in key +func (c *MockChannel) OrgConfigForKey(key string, defaultValue interface{}) interface{} { + value, found := c.orgConfig[key] + if !found { + return defaultValue + } + return value +} + +// SetRoles sets the role on the channel +func (c *MockChannel) SetRoles(roles []courier.ChannelRole) { + c.role = fmt.Sprint(roles) +} + +// Roles returns the roles of this channel +func (c *MockChannel) Roles() []courier.ChannelRole { + roles := []courier.ChannelRole{} + for _, char := range strings.Split(c.role, "") { + roles = append(roles, courier.ChannelRole(char)) + } + return roles +} + +// HasRole returns whether the passed in channel supports the passed role +func (c *MockChannel) HasRole(role courier.ChannelRole) bool { + for _, r := range c.Roles() { + if r == role { + return true + } + } + return false +} + +// NewMockChannel creates a new mock channel for the passed in type, address, country and config +func NewMockChannel(uuid string, channelType string, address string, country string, config map[string]interface{}) *MockChannel { + cUUID, _ := courier.NewChannelUUID(uuid) + + channel := &MockChannel{ + uuid: cUUID, + channelType: courier.ChannelType(channelType), + schemes: []string{urns.TelScheme}, + address: courier.ChannelAddress(address), + country: country, + config: config, + role: "SR", + orgConfig: map[string]interface{}{}, + } + return channel +} diff --git a/test/channel_event.go b/test/channel_event.go new file mode 100644 index 000000000..77b43665d --- /dev/null +++ b/test/channel_event.go @@ -0,0 +1,46 @@ +package test + +import ( + "time" + + "github.com/nyaruka/courier" + "github.com/nyaruka/gocommon/urns" +) + +type mockChannelEvent struct { + channel courier.Channel + eventType courier.ChannelEventType + urn urns.URN + createdOn time.Time + occurredOn time.Time + + contactName string + extra map[string]interface{} + + logs []*courier.ChannelLog +} + +func (e *mockChannelEvent) EventID() int64 { return 0 } +func (e *mockChannelEvent) ChannelUUID() courier.ChannelUUID { return e.channel.UUID() } +func (e *mockChannelEvent) EventType() courier.ChannelEventType { return e.eventType } +func (e *mockChannelEvent) CreatedOn() time.Time { return e.createdOn } +func (e *mockChannelEvent) OccurredOn() time.Time { return e.occurredOn } +func (e *mockChannelEvent) Extra() map[string]interface{} { return e.extra } +func (e *mockChannelEvent) ContactName() string { return e.contactName } +func (e *mockChannelEvent) URN() urns.URN { return e.urn } + +func (e *mockChannelEvent) WithExtra(extra map[string]interface{}) courier.ChannelEvent { + e.extra = extra + return e +} +func (e *mockChannelEvent) WithContactName(name string) courier.ChannelEvent { + e.contactName = name + return e +} +func (e *mockChannelEvent) WithOccurredOn(time time.Time) courier.ChannelEvent { + e.occurredOn = time + return e +} + +func (e *mockChannelEvent) Logs() []*courier.ChannelLog { return e.logs } +func (e *mockChannelEvent) AddLog(log *courier.ChannelLog) { e.logs = append(e.logs, log) } diff --git a/test/contact.go b/test/contact.go new file mode 100644 index 000000000..4952780b7 --- /dev/null +++ b/test/contact.go @@ -0,0 +1,15 @@ +package test + +import ( + "github.com/nyaruka/courier" + "github.com/nyaruka/gocommon/urns" +) + +type mockContact struct { + channel courier.Channel + urn urns.URN + auth string + uuid courier.ContactUUID +} + +func (c *mockContact) UUID() courier.ContactUUID { return c.uuid } diff --git a/test/media.go b/test/media.go new file mode 100644 index 000000000..f07b87adf --- /dev/null +++ b/test/media.go @@ -0,0 +1,36 @@ +package test + +import "github.com/nyaruka/courier" + +type mockMedia struct { + name string + contentType string + url string + size int + width int + height int + duration int + alternates []courier.Media +} + +func (m *mockMedia) Name() string { return m.name } +func (m *mockMedia) ContentType() string { return m.contentType } +func (m *mockMedia) URL() string { return m.url } +func (m *mockMedia) Size() int { return m.size } +func (m *mockMedia) Width() int { return m.width } +func (m *mockMedia) Height() int { return m.height } +func (m *mockMedia) Duration() int { return m.duration } +func (m *mockMedia) Alternates() []courier.Media { return m.alternates } + +func NewMockMedia(name, contentType, url string, size, width, height, duration int, alternates []courier.Media) courier.Media { + return &mockMedia{ + name: name, + contentType: contentType, + url: url, + size: size, + width: width, + height: height, + duration: duration, + alternates: alternates, + } +} diff --git a/test/msg.go b/test/msg.go new file mode 100644 index 000000000..7ab7b76b7 --- /dev/null +++ b/test/msg.go @@ -0,0 +1,96 @@ +package test + +import ( + "encoding/json" + "time" + + "github.com/nyaruka/courier" + "github.com/nyaruka/gocommon/urns" +) + +type mockMsg struct { + id courier.MsgID + uuid courier.MsgUUID + channel courier.Channel + urn urns.URN + urnAuth string + text string + attachments []string + externalID string + contactName string + highPriority bool + quickReplies []string + topic string + responseToExternalID string + metadata json.RawMessage + alreadyWritten bool + isResend bool + + flow *courier.FlowReference + + receivedOn *time.Time + sentOn *time.Time + wiredOn *time.Time +} + +func NewMockMsg(id courier.MsgID, uuid courier.MsgUUID, channel courier.Channel, urn urns.URN, text string) courier.Msg { + return &mockMsg{ + id: id, + uuid: uuid, + channel: channel, + urn: urn, + text: text, + } +} + +func (m *mockMsg) SessionStatus() string { return "" } +func (m *mockMsg) Flow() *courier.FlowReference { return m.flow } + +func (m *mockMsg) FlowName() string { + if m.flow == nil { + return "" + } + return m.flow.Name +} + +func (m *mockMsg) FlowUUID() string { + if m.flow == nil { + return "" + } + return m.flow.UUID +} + +func (m *mockMsg) Channel() courier.Channel { return m.channel } +func (m *mockMsg) ID() courier.MsgID { return m.id } +func (m *mockMsg) EventID() int64 { return int64(m.id) } +func (m *mockMsg) UUID() courier.MsgUUID { return m.uuid } +func (m *mockMsg) Text() string { return m.text } +func (m *mockMsg) Attachments() []string { return m.attachments } +func (m *mockMsg) ExternalID() string { return m.externalID } +func (m *mockMsg) URN() urns.URN { return m.urn } +func (m *mockMsg) URNAuth() string { return m.urnAuth } +func (m *mockMsg) ContactName() string { return m.contactName } +func (m *mockMsg) HighPriority() bool { return m.highPriority } +func (m *mockMsg) QuickReplies() []string { return m.quickReplies } +func (m *mockMsg) Topic() string { return m.topic } +func (m *mockMsg) ResponseToExternalID() string { return m.responseToExternalID } +func (m *mockMsg) Metadata() json.RawMessage { return m.metadata } +func (m *mockMsg) IsResend() bool { return m.isResend } + +func (m *mockMsg) ReceivedOn() *time.Time { return m.receivedOn } +func (m *mockMsg) SentOn() *time.Time { return m.sentOn } +func (m *mockMsg) WiredOn() *time.Time { return m.wiredOn } + +func (m *mockMsg) WithContactName(name string) courier.Msg { m.contactName = name; return m } +func (m *mockMsg) WithURNAuth(auth string) courier.Msg { m.urnAuth = auth; return m } +func (m *mockMsg) WithReceivedOn(date time.Time) courier.Msg { m.receivedOn = &date; return m } +func (m *mockMsg) WithExternalID(id string) courier.Msg { m.externalID = id; return m } +func (m *mockMsg) WithID(id courier.MsgID) courier.Msg { m.id = id; return m } +func (m *mockMsg) WithUUID(uuid courier.MsgUUID) courier.Msg { m.uuid = uuid; return m } +func (m *mockMsg) WithAttachment(url string) courier.Msg { + m.attachments = append(m.attachments, url) + return m +} +func (m *mockMsg) WithMetadata(metadata json.RawMessage) courier.Msg { m.metadata = metadata; return m } + +func (m *mockMsg) WithFlow(flow *courier.FlowReference) courier.Msg { m.flow = flow; return m } diff --git a/test/status.go b/test/status.go new file mode 100644 index 000000000..f6ffe8a36 --- /dev/null +++ b/test/status.go @@ -0,0 +1,48 @@ +package test + +import ( + "time" + + "github.com/nyaruka/courier" + "github.com/nyaruka/gocommon/urns" +) + +type mockMsgStatus struct { + channel courier.Channel + id courier.MsgID + oldURN urns.URN + newURN urns.URN + externalID string + status courier.MsgStatusValue + createdOn time.Time + + logs []*courier.ChannelLog +} + +func (m *mockMsgStatus) ChannelUUID() courier.ChannelUUID { return m.channel.UUID() } +func (m *mockMsgStatus) ID() courier.MsgID { return m.id } +func (m *mockMsgStatus) EventID() int64 { return int64(m.id) } + +func (m *mockMsgStatus) SetUpdatedURN(old, new urns.URN) error { + m.oldURN = old + m.newURN = new + return nil +} +func (m *mockMsgStatus) UpdatedURN() (urns.URN, urns.URN) { + return m.oldURN, m.newURN +} +func (m *mockMsgStatus) HasUpdatedURN() bool { + if m.oldURN != urns.NilURN && m.newURN != urns.NilURN { + return true + } + return false +} + +func (m *mockMsgStatus) ExternalID() string { return m.externalID } +func (m *mockMsgStatus) SetExternalID(id string) { m.externalID = id } + +func (m *mockMsgStatus) Status() courier.MsgStatusValue { return m.status } +func (m *mockMsgStatus) SetStatus(status courier.MsgStatusValue) { m.status = status } + +func (m *mockMsgStatus) Logs() []*courier.ChannelLog { return m.logs } +func (m *mockMsgStatus) AddLog(log *courier.ChannelLog) { m.logs = append(m.logs, log) } diff --git a/test/utils.go b/test/utils.go new file mode 100644 index 000000000..f1d0c94e7 --- /dev/null +++ b/test/utils.go @@ -0,0 +1,11 @@ +package test + +import "os" + +func ReadFile(path string) []byte { + d, err := os.ReadFile(path) + if err != nil { + panic(err) + } + return d +} From 2e3de63b27fdc93db5835d37dbb2c5cae8397c5b Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 10 Aug 2022 13:57:30 -0500 Subject: [PATCH 058/294] Update CHANGELOG.md for v7.5.8 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f749449a..8f34f574a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.8 +---------- + * Move testing code out of courier package and into new test package + * Rework some handler sending to record logs via a logger rather than on the status object + v7.5.7 ---------- * Convert remaining channel types to use httpx.Trace From dd97d09b6c3bb3cfa0fb8ca7abca6c4e2b69becc Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 10 Aug 2022 14:49:57 -0500 Subject: [PATCH 059/294] Handler send tests should assert all logged errors --- channel_log.go | 9 +- handlers/arabiacell/arabiacell_test.go | 2 + handlers/blackmyna/blackmyna_test.go | 2 +- handlers/burstsms/burstsms_test.go | 60 ++- handlers/clickatell/clickatell_test.go | 85 ++-- handlers/clicksend/clicksend_test.go | 77 ++-- handlers/dart/dart_test.go | 100 +++-- handlers/dmark/dmark_test.go | 44 +- handlers/external/external_test.go | 488 ++++++++++++++--------- handlers/facebookapp/facebookapp_test.go | 10 +- handlers/firebase/firebase_test.go | 114 ++++-- handlers/i2sms/i2sms_test.go | 60 ++- handlers/infobip/infobip_test.go | 88 ++-- handlers/jiochat/jiochat_test.go | 2 +- handlers/junebug/junebug_test.go | 71 ++-- handlers/macrokiosk/macrokiosk_test.go | 2 +- handlers/mblox/mblox_test.go | 2 +- handlers/messangi/messangi_test.go | 58 ++- handlers/mtarget/mtarget_test.go | 76 ++-- handlers/novo/novo_test.go | 57 ++- handlers/plivo/plivo_test.go | 2 +- handlers/test.go | 16 +- handlers/viber/viber_test.go | 5 +- handlers/wechat/wechat_test.go | 2 +- handlers/whatsapp/whatsapp_test.go | 10 +- handlers/zenvia/zenvia_test.go | 88 ++-- handlers/zenviaold/zenviaold_test.go | 40 +- 27 files changed, 1004 insertions(+), 566 deletions(-) diff --git a/channel_log.go b/channel_log.go index 274ca25d3..303465479 100644 --- a/channel_log.go +++ b/channel_log.go @@ -130,7 +130,8 @@ type ChannelLogger struct { type_ ChannelLogType msg Msg - logs []*ChannelLog + errors []string + logs []*ChannelLog } func NewChannelLoggerForSend(msg Msg) *ChannelLogger { @@ -150,6 +151,8 @@ func (l *ChannelLogger) HTTP(t *httpx.Trace) { } func (l *ChannelLogger) Error(err error) { + l.errors = append(l.errors, err.Error()) + // if we have an existing log which isn't already an error, update it if len(l.logs) > 0 && l.logs[len(l.logs)-1].Error == "" { l.logs[len(l.logs)-1].Error = err.Error() @@ -159,6 +162,10 @@ func (l *ChannelLogger) Error(err error) { } } +func (l *ChannelLogger) Errors() []string { + return l.errors +} + func (l *ChannelLogger) Logs() []*ChannelLog { return l.logs } diff --git a/handlers/arabiacell/arabiacell_test.go b/handlers/arabiacell/arabiacell_test.go index 8c490c878..4e9aa1914 100644 --- a/handlers/arabiacell/arabiacell_test.go +++ b/handlers/arabiacell/arabiacell_test.go @@ -70,6 +70,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `not xml`, MockResponseStatus: 200, ExpectedStatus: "E", + ExpectedErrors: []string{"EOF"}, SendPrep: setSendURL, }, { @@ -79,6 +80,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `501failure`, MockResponseStatus: 200, ExpectedStatus: "F", + ExpectedErrors: []string{"Received invalid response code: 501"}, SendPrep: setSendURL, }, { diff --git a/handlers/blackmyna/blackmyna_test.go b/handlers/blackmyna/blackmyna_test.go index 65681ca39..5ad017704 100644 --- a/handlers/blackmyna/blackmyna_test.go +++ b/handlers/blackmyna/blackmyna_test.go @@ -94,7 +94,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 200, - ExpectedError: "no external id returned in body", + ExpectedErrors: []string{"no external id returned in body"}, ExpectedPostParams: map[string]string{"message": `No External ID`, "address": "+250788383383", "senderaddress": "2020"}, ExpectedStatus: "E", SendPrep: setSendURL, diff --git a/handlers/burstsms/burstsms_test.go b/handlers/burstsms/burstsms_test.go index a9a67b21e..25fe79f0c 100644 --- a/handlers/burstsms/burstsms_test.go +++ b/handlers/burstsms/burstsms_test.go @@ -48,31 +48,51 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", ExpectedExternalID: "19835", - MockResponseBody: `{ "message_id": 19835, "recipients": 3, "cost": 1.000 }`, MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{ "message_id": 19835, "recipients": 3, "cost": 1.000 }`, + MockResponseStatus: 200, ExpectedPostParams: map[string]string{ "to": "250788383383", "message": "Simple Message ☺\nhttps://foo.bar/image.jpg", "from": "2020", }, - SendPrep: setSendURL}, - {Label: "Invalid JSON", - MsgText: "Invalid JSON", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `not json`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Error Response", - MsgText: "Error Response", MsgURN: "tel:+250788383383", - ExpectedStatus: "F", - MockResponseBody: `{ "message_id": 0 }`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `Bad Gateway`, MockResponseStatus: 501, - SendPrep: setSendURL}, + ExpectedStatus: "W", + ExpectedExternalID: "19835", + SendPrep: setSendURL, + }, + { + Label: "Invalid JSON", + MsgText: "Invalid JSON", + MsgURN: "tel:+250788383383", + MockResponseBody: `not json`, + MockResponseStatus: 200, + ExpectedStatus: "E", + ExpectedErrors: []string{"invalid character 'o' in literal null (expecting 'u')"}, + SendPrep: setSendURL, + }, + { + Label: "Error Response", + MsgText: "Error Response", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "message_id": 0 }`, + MockResponseStatus: 200, + ExpectedStatus: "F", + ExpectedErrors: []string{"Received invalid message id: 0"}, + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `Bad Gateway`, + MockResponseStatus: 501, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/clickatell/clickatell_test.go b/handlers/clickatell/clickatell_test.go index 3bf2072ea..dd980bd77 100644 --- a/handlers/clickatell/clickatell_test.go +++ b/handlers/clickatell/clickatell_test.go @@ -19,36 +19,61 @@ var successSendResponse = `{"messages":[{"apiMessageId":"id1002","accepted":true var failSendResponse = `{"messages":[],"error":"Two-Way integration error - From number is not related to integration"}` var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", ExpectedExternalID: "id1002", - ExpectedURLParams: map[string]string{"content": "Simple Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, - MockResponseBody: successSendResponse, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: "Unicode ☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", ExpectedExternalID: "id1002", - ExpectedURLParams: map[string]string{"content": "Unicode ☺", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, - MockResponseBody: successSendResponse, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", ExpectedExternalID: "id1002", - ExpectedURLParams: map[string]string{"content": "My pic!\nhttps://foo.bar/image.jpg", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, - MockResponseBody: successSendResponse, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - ExpectedURLParams: map[string]string{"content": "Error Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, - MockResponseBody: `Error`, MockResponseStatus: 400, - SendPrep: setSendURL}, - {Label: "Error Response", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - ExpectedURLParams: map[string]string{"content": "Error Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, - MockResponseBody: failSendResponse, MockResponseStatus: 200, - SendPrep: setSendURL}, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: successSendResponse, + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"content": "Simple Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, + ExpectedStatus: "W", + ExpectedExternalID: "id1002", + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "Unicode ☺", + MsgURN: "tel:+250788383383", + MockResponseBody: successSendResponse, + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"content": "Unicode ☺", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, + ExpectedStatus: "W", + ExpectedExternalID: "id1002", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: successSendResponse, + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"content": "My pic!\nhttps://foo.bar/image.jpg", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, + ExpectedStatus: "W", + ExpectedExternalID: "id1002", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `Error`, + MockResponseStatus: 400, + ExpectedURLParams: map[string]string{"content": "Error Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error Response", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: failSendResponse, + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"content": "Error Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, + ExpectedStatus: "E", + ExpectedErrors: []string{"Key path not found"}, + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/clicksend/clicksend_test.go b/handlers/clicksend/clicksend_test.go index 25c10d20c..b7033b698 100644 --- a/handlers/clicksend/clicksend_test.go +++ b/handlers/clicksend/clicksend_test.go @@ -96,35 +96,60 @@ const failureResponse = `{ }` var sendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - ExpectedHeaders: map[string]string{"Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="}, - MockResponseBody: successResponse, MockResponseStatus: 200, ExpectedExternalID: "BF7AD270-0DE2-418B-B606-71D527D9C1AE", + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: successResponse, + MockResponseStatus: 200, ExpectedRequestBody: `{"messages":[{"to":"+250788383383","from":"2020","body":"Simple Message","source":"courier"}]}`, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: "☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: successResponse, MockResponseStatus: 200, ExpectedExternalID: "BF7AD270-0DE2-418B-B606-71D527D9C1AE", + ExpectedHeaders: map[string]string{"Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="}, + ExpectedStatus: "W", + ExpectedExternalID: "BF7AD270-0DE2-418B-B606-71D527D9C1AE", + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "tel:+250788383383", + MockResponseBody: successResponse, + MockResponseStatus: 200, ExpectedRequestBody: `{"messages":[{"to":"+250788383383","from":"2020","body":"☺","source":"courier"}]}`, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: successResponse, MockResponseStatus: 200, ExpectedExternalID: "BF7AD270-0DE2-418B-B606-71D527D9C1AE", + ExpectedStatus: "W", + ExpectedExternalID: "BF7AD270-0DE2-418B-B606-71D527D9C1AE", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: successResponse, + MockResponseStatus: 200, ExpectedRequestBody: `{"messages":[{"to":"+250788383383","from":"2020","body":"My pic!\nhttps://foo.bar/image.jpg","source":"courier"}]}`, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Sending", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `[{"Response": "101"}]`, MockResponseStatus: 403, - SendPrep: setSendURL}, - {Label: "Failure Response", - MsgText: "Error Sending", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: failureResponse, MockResponseStatus: 200, - SendPrep: setSendURL}, + ExpectedExternalID: "BF7AD270-0DE2-418B-B606-71D527D9C1AE", + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Sending", + MsgURN: "tel:+250788383383", + MockResponseBody: `[{"Response": "101"}]`, + MockResponseStatus: 403, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Failure Response", + MsgText: "Error Sending", + MsgURN: "tel:+250788383383", + MockResponseBody: failureResponse, + MockResponseStatus: 200, + ExpectedStatus: "E", + ExpectedErrors: []string{"received non SUCCESS status: FAILURE"}, + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/dart/dart_test.go b/handlers/dart/dart_test.go index 68b0d7a94..c15b82e99 100644 --- a/handlers/dart/dart_test.go +++ b/handlers/dart/dart_test.go @@ -57,43 +57,69 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, - MockResponseBody: "000", MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Long Send", - MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - ExpectedURLParams: map[string]string{"message": "I need to keep adding more things to make it work", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10.2"}, - MockResponseBody: "000", MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - ExpectedURLParams: map[string]string{"message": "My pic!\nhttps://foo.bar/image.jpg", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, - MockResponseBody: "000", MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - ExpectedURLParams: map[string]string{"message": "Error Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, - MockResponseBody: `Error`, MockResponseStatus: 400, - SendPrep: setSendURL}, - {Label: "Authentication Error", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, - MockResponseBody: "001", MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Account Expired", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, - MockResponseBody: "101", MockResponseStatus: 200, - SendPrep: setSendURL}, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: "000", + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Long Send", + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + MockResponseBody: "000", + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"message": "I need to keep adding more things to make it work", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10.2"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: "000", + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"message": "My pic!\nhttps://foo.bar/image.jpg", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `Error`, + MockResponseStatus: 400, + ExpectedURLParams: map[string]string{"message": "Error Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Authentication Error", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: "001", + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, + ExpectedStatus: "E", + ExpectedErrors: []string{"Error 001: Authentication Error"}, + SendPrep: setSendURL, + }, + { + Label: "Account Expired", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: "101", + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, + ExpectedStatus: "E", + ExpectedErrors: []string{"Error 101: Account expired or invalid parameters"}, + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/dmark/dmark_test.go b/handlers/dmark/dmark_test.go index be1f2bfe6..bbf921396 100644 --- a/handlers/dmark/dmark_test.go +++ b/handlers/dmark/dmark_test.go @@ -57,27 +57,41 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", ExpectedExternalID: "6b1c15d3-cba2-46f7-9a25-78265e58057d", - MockResponseBody: `{ "type": "MT", "sms_id": "6b1c15d3-cba2-46f7-9a25-78265e58057d" }`, MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + ExpectedExternalID: "6b1c15d3-cba2-46f7-9a25-78265e58057d", + MockResponseBody: `{ "type": "MT", "sms_id": "6b1c15d3-cba2-46f7-9a25-78265e58057d" }`, + MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "Token Authy"}, ExpectedPostParams: map[string]string{"text": "Simple Message ☺", "receiver": "250788383383", "sender": "2020", "dlr_url": "https://localhost/c/dk/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%s"}, - SendPrep: setSendURL}, - {Label: "Invalid Body", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 200, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Invalid Body", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "error": "failed" }`, + MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "Token Authy"}, ExpectedPostParams: map[string]string{"text": "Error Message", "receiver": "250788383383", "sender": "2020"}, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, + ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get sms_id from body"}, + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "error": "failed" }`, + MockResponseStatus: 401, ExpectedHeaders: map[string]string{"Authorization": "Token Authy"}, ExpectedPostParams: map[string]string{"text": "Error Message", "receiver": "250788383383", "sender": "2020"}, - SendPrep: setSendURL}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/external/external_test.go b/handlers/external/external_test.go index 8bc2c0763..681a7f668 100644 --- a/handlers/external/external_test.go +++ b/handlers/external/external_test.go @@ -131,263 +131,387 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var longSendTestCases = []ChannelSendTestCase{ - {Label: "Long Send", + { + Label: "Long Send", MsgText: "This is a long message that will be longer than 30....... characters", MsgURN: "tel:+250788383383", - MsgQuickReplies: []string{"One"}, - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"text": "characters", "to": "+250788383383", "from": "2020", "quick_reply": "One"}, - SendPrep: setSendURL}, + MsgQuickReplies: []string{"One"}, + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "characters", "to": "+250788383383", "from": "2020", "quick_reply": "One"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } var getSendSmartEncodingTestCases = []ChannelSendTestCase{ - {Label: "Smart Encoding", - MsgText: "Fancy “Smart” Quotes", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"text": `Fancy "Smart" Quotes`, "to": "+250788383383", "from": "2020"}, - ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + { + Label: "Smart Encoding", + MsgText: "Fancy “Smart” Quotes", + MsgURN: "tel:+250788383383", + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": `Fancy "Smart" Quotes`, "to": "+250788383383", "from": "2020"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } var postSendSmartEncodingTestCases = []ChannelSendTestCase{ - {Label: "Smart Encoding", - MsgText: "Fancy “Smart” Quotes", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + { + Label: "Smart Encoding", + MsgText: "Fancy “Smart” Quotes", + MsgURN: "tel:+250788383383", + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": `Fancy "Smart" Quotes`, "to": "+250788383383", "from": "2020"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } var getSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"text": "Simple Message", "to": "+250788383383", "from": "2020"}, - ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, - {Label: "Unicode Send", + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "Simple Message", "to": "+250788383383", "from": "2020"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", MsgText: "☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"text": "☺", "to": "+250788383383", "from": "2020"}, - ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: "1: Unknown channel", MockResponseStatus: 401, - ExpectedURLParams: map[string]string{"text": `Error Message`, "to": "+250788383383"}, - ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: `0: Accepted for delivery`, MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "+250788383383", "from": "2020"}, - ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "☺", "to": "+250788383383", "from": "2020"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: "1: Unknown channel", + MockResponseStatus: 401, + ExpectedURLParams: map[string]string{"text": `Error Message`, "to": "+250788383383"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `0: Accepted for delivery`, + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "+250788383383", "from": "2020"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } var postSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "+250788383383", "from": "2020"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: "☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "tel:+250788383383", + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "☺", "to": "+250788383383", "from": "2020"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: "1: Unknown channel", MockResponseStatus: 401, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: "1: Unknown channel", + MockResponseStatus: 401, ExpectedPostParams: map[string]string{"text": `Error Message`, "to": "+250788383383"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MockResponseBody: `0: Accepted for delivery`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "+250788383383", "from": "2020"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } var postSendCustomContentTypeTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded; charset=utf-8"}, - SendPrep: setSendURL}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } var jsonSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, ExpectedRequestBody: `{ "to":"+250788383383", "text":"Simple Message", "from":"2020", "quick_replies":[] }`, ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: `☺ "hi!"`, MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: `☺ "hi!"`, + MsgURN: "tel:+250788383383", + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, ExpectedRequestBody: `{ "to":"+250788383383", "text":"☺ \"hi!\"", "from":"2020", "quick_replies":[] }`, ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: "1: Unknown channel", MockResponseStatus: 401, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: "1: Unknown channel", + MockResponseStatus: 401, ExpectedRequestBody: `{ "to":"+250788383383", "text":"Error Message", "from":"2020", "quick_replies":[] }`, ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: `0: Accepted for delivery`, MockResponseStatus: 200, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `0: Accepted for delivery`, + MockResponseStatus: 200, ExpectedRequestBody: `{ "to":"+250788383383", "text":"My pic!\nhttps://foo.bar/image.jpg", "from":"2020", "quick_replies":[] }`, ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, + ExpectedStatus: "W", SendPrep: setSendURL}, - {Label: "Send Quick Replies", - MsgText: "Some message", MsgURN: "tel:+250788383383", MsgQuickReplies: []string{"One", "Two", "Three"}, - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + { + Label: "Send Quick Replies", + MsgText: "Some message", + MsgURN: "tel:+250788383383", + MsgQuickReplies: []string{"One", "Two", "Three"}, + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, ExpectedRequestBody: `{ "to":"+250788383383", "text":"Some message", "from":"2020", "quick_replies":["One","Two","Three"] }`, ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - SendPrep: setSendURL}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } var jsonLongSendTestCases = []ChannelSendTestCase{ - {Label: "Send Quick Replies", - MsgText: "This is a long message that will be longer than 30....... characters", MsgURN: "tel:+250788383383", - MsgQuickReplies: []string{"One", "Two", "Three"}, - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + { + Label: "Send Quick Replies", + MsgText: "This is a long message that will be longer than 30....... characters", + MsgURN: "tel:+250788383383", + MsgQuickReplies: []string{"One", "Two", "Three"}, + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, ExpectedRequestBody: `{ "to":"+250788383383", "text":"characters", "from":"2020", "quick_replies":["One","Two","Three"] }`, ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - SendPrep: setSendURL}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } var xmlSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, ExpectedRequestBody: `+250788383383Simple Message2020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: `☺`, MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: `☺`, + MsgURN: "tel:+250788383383", + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, ExpectedRequestBody: `+2507883833832020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: "1: Unknown channel", MockResponseStatus: 401, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: "1: Unknown channel", + MockResponseStatus: 401, ExpectedRequestBody: `+250788383383Error Message2020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: `0: Accepted for delivery`, MockResponseStatus: 200, - ExpectedRequestBody: `+250788383383My pic! https://foo.bar/image.jpg2020` + - ``, - ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, - {Label: "Send Quick Replies", - MsgText: "Some message", MsgURN: "tel:+250788383383", MsgQuickReplies: []string{"One", "Two", "Three"}, - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, - ExpectedRequestBody: "+250788383383Some message2020" + - "OneTwoThree", - ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `0: Accepted for delivery`, + MockResponseStatus: 200, + ExpectedRequestBody: `+250788383383My pic! https://foo.bar/image.jpg2020`, + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Quick Replies", + MsgText: "Some message", + MsgURN: "tel:+250788383383", + MsgQuickReplies: []string{"One", "Two", "Three"}, + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, + ExpectedRequestBody: "+250788383383Some message2020OneTwoThree", + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } var xmlLongSendTestCases = []ChannelSendTestCase{ - {Label: "Send Quick Replies", - MsgText: "This is a long message that will be longer than 30....... characters", MsgURN: "tel:+250788383383", - MsgQuickReplies: []string{"One", "Two", "Three"}, - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, - ExpectedRequestBody: "+250788383383characters2020" + - "OneTwoThree", - ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, + { + Label: "Send Quick Replies", + MsgText: "This is a long message that will be longer than 30....... characters", + MsgURN: "tel:+250788383383", + MsgQuickReplies: []string{"One", "Two", "Three"}, + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, + ExpectedRequestBody: "+250788383383characters2020OneTwoThree", + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } var xmlSendWithResponseContentTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "0", MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + MockResponseBody: "0", + MockResponseStatus: 200, ExpectedRequestBody: `+250788383383Simple Message2020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: `☺`, MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "0", MockResponseStatus: 200, + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: `☺`, + MsgURN: "tel:+250788383383", + MockResponseBody: "0", + MockResponseStatus: 200, ExpectedRequestBody: `+2507883833832020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: "0", MockResponseStatus: 401, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: "0", + MockResponseStatus: 401, ExpectedRequestBody: `+250788383383Error Message2020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, - {Label: "Error Sending with 200 status code", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: "1", MockResponseStatus: 200, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error Sending with 200 status code", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: "1", + MockResponseStatus: 200, ExpectedRequestBody: `+250788383383Error Message2020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: `0`, MockResponseStatus: 200, - ExpectedRequestBody: `+250788383383My pic! https://foo.bar/image.jpg2020` + - ``, - ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, - {Label: "Send Quick Replies", - MsgText: "Some message", MsgURN: "tel:+250788383383", MsgQuickReplies: []string{"One", "Two", "Three"}, - ExpectedStatus: "W", - MockResponseBody: "0", MockResponseStatus: 200, - ExpectedRequestBody: `+250788383383Some message2020` + - `OneTwoThree`, - ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - SendPrep: setSendURL}, + ExpectedStatus: "E", + ExpectedErrors: []string{"Received invalid response content: 1"}, + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `0`, + MockResponseStatus: 200, + ExpectedRequestBody: `+250788383383My pic! https://foo.bar/image.jpg2020`, + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Quick Replies", + MsgText: "Some message", + MsgURN: "tel:+250788383383", + MsgQuickReplies: []string{"One", "Two", "Three"}, + MockResponseBody: "0", + MockResponseStatus: 200, + ExpectedRequestBody: `+250788383383Some message2020OneTwoThree`, + ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } var nationalGetSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"text": "Simple Message", "to": "788383383", "from": "2020"}, - ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "Simple Message", "to": "788383383", "from": "2020"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 2b0179a2f..86b4ad7d8 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -759,11 +759,11 @@ var SendTestCasesWAC = []ChannelSendTestCase{ SendPrep: setSendURL, }, { - Label: "Template Invalid Language", - MsgText: "templated message", - MsgURN: "whatsapp:250788123123", - MsgMetadata: json.RawMessage(`{"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}}`), - ExpectedError: `unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, + Label: "Template Invalid Language", + MsgText: "templated message", + MsgURN: "whatsapp:250788123123", + MsgMetadata: json.RawMessage(`{"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}}`), + ExpectedErrors: []string{`unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`}, }, { Label: "Interactive Button Message Send", diff --git a/handlers/firebase/firebase_test.go b/handlers/firebase/firebase_test.go index 9bd0f76f9..9494db480 100644 --- a/handlers/firebase/firebase_test.go +++ b/handlers/firebase/firebase_test.go @@ -73,53 +73,95 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var notificationSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "fcm:250788123123", MsgURNAuth: "auth1", - ExpectedStatus: "W", ExpectedExternalID: "123456", - MockResponseBody: `{"success":1, "multicast_id": 123456}`, MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "fcm:250788123123", + MsgURNAuth: "auth1", + MockResponseBody: `{"success":1, "multicast_id": 123456}`, + MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "key=FCMKey"}, ExpectedRequestBody: `{"data":{"type":"rapidpro","title":"FCMTitle","message":"Simple Message","message_id":10,"session_status":""},"notification":{"title":"FCMTitle","body":"Simple Message"},"content_available":true,"to":"auth1","priority":"high"}`, - SendPrep: setSendURL}, + ExpectedStatus: "W", + ExpectedExternalID: "123456", + SendPrep: setSendURL, + }, } var sendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "fcm:250788123123", MsgURNAuth: "auth1", - ExpectedStatus: "W", ExpectedExternalID: "123456", - MockResponseBody: `{"success":1, "multicast_id": 123456}`, MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "fcm:250788123123", + MsgURNAuth: "auth1", + MockResponseBody: `{"success":1, "multicast_id": 123456}`, + MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "key=FCMKey"}, ExpectedRequestBody: `{"data":{"type":"rapidpro","title":"FCMTitle","message":"Simple Message","message_id":10,"session_status":""},"content_available":false,"to":"auth1","priority":"high"}`, - SendPrep: setSendURL}, - {Label: "Long Message", - MsgText: longMsg, - MsgURN: "fcm:250788123123", MsgURNAuth: "auth1", - ExpectedStatus: "W", ExpectedExternalID: "123456", - MockResponseBody: `{"success":1, "multicast_id": 123456}`, MockResponseStatus: 200, + ExpectedStatus: "W", + ExpectedExternalID: "123456", + SendPrep: setSendURL, + }, + { + Label: "Long Message", + MsgText: longMsg, + MsgURN: "fcm:250788123123", + MsgURNAuth: "auth1", + MockResponseBody: `{"success":1, "multicast_id": 123456}`, + MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "key=FCMKey"}, ExpectedRequestBody: `{"data":{"type":"rapidpro","title":"FCMTitle","message":"ate ac.","message_id":10,"session_status":""},"content_available":false,"to":"auth1","priority":"high"}`, - SendPrep: setSendURL}, - {Label: "Quick Reply", - MsgText: "Simple Message", MsgURN: "fcm:250788123123", MsgURNAuth: "auth1", MsgQuickReplies: []string{"yes", "no"}, MsgAttachments: []string{"image/jpeg:https://foo.bar"}, - ExpectedStatus: "W", ExpectedExternalID: "123456", - MockResponseBody: `{"success":1, "multicast_id": 123456}`, MockResponseStatus: 200, + ExpectedStatus: "W", + ExpectedExternalID: "123456", + SendPrep: setSendURL, + }, + { + Label: "Quick Reply", + MsgText: "Simple Message", + MsgURN: "fcm:250788123123", + MsgURNAuth: "auth1", + MsgQuickReplies: []string{"yes", "no"}, + MsgAttachments: []string{"image/jpeg:https://foo.bar"}, + MockResponseBody: `{"success":1, "multicast_id": 123456}`, + MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "key=FCMKey"}, ExpectedRequestBody: `{"data":{"type":"rapidpro","title":"FCMTitle","message":"Simple Message\nhttps://foo.bar","message_id":10,"session_status":"","quick_replies":["yes","no"]},"content_available":false,"to":"auth1","priority":"high"}`, - SendPrep: setSendURL}, - {Label: "Error", - MsgText: "Error", MsgURN: "fcm:250788123123", MsgURNAuth: "auth1", - ExpectedStatus: "E", - MockResponseBody: `{ "success": 0 }`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "No Multicast ID", - MsgText: "Error", MsgURN: "fcm:250788123123", MsgURNAuth: "auth1", - ExpectedStatus: "E", - MockResponseBody: `{ "success": 1 }`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Request Error", - MsgText: "Error", MsgURN: "fcm:250788123123", MsgURNAuth: "auth1", - ExpectedStatus: "E", - MockResponseBody: `{ "success": 0 }`, MockResponseStatus: 500, - SendPrep: setSendURL}, + ExpectedStatus: "W", + ExpectedExternalID: "123456", + SendPrep: setSendURL, + }, + { + Label: "Error", + MsgText: "Error", + MsgURN: "fcm:250788123123", + MsgURNAuth: "auth1", + MockResponseBody: `{ "success": 0 }`, + MockResponseStatus: 200, + ExpectedStatus: "E", + ExpectedErrors: []string{"received non-1 value for success in response"}, + SendPrep: setSendURL, + }, + { + Label: "No Multicast ID", + MsgText: "Error", + MsgURN: "fcm:250788123123", + MsgURNAuth: "auth1", + MockResponseBody: `{ "success": 1 }`, + MockResponseStatus: 200, + ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get multicast_id from response"}, + SendPrep: setSendURL, + }, + { + Label: "Request Error", + MsgText: "Error", + MsgURN: "fcm:250788123123", + MsgURNAuth: "auth1", + MockResponseBody: `{ "success": 0 }`, + MockResponseStatus: 500, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/i2sms/i2sms_test.go b/handlers/i2sms/i2sms_test.go index b06da3b17..ed4c7f208 100644 --- a/handlers/i2sms/i2sms_test.go +++ b/handlers/i2sms/i2sms_test.go @@ -39,32 +39,52 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", ExpectedExternalID: "5b8fc97d58795484819426", - MockResponseBody: `{"result":{"session_id":"5b8fc97d58795484819426"}, "error_code": "00", "error_desc": "Success"}`, MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{"result":{"session_id":"5b8fc97d58795484819426"}, "error_code": "00", "error_desc": "Success"}`, + MockResponseStatus: 200, ExpectedPostParams: map[string]string{ "action": "send_single", "mobile": "250788383383", "message": "Simple Message ☺\nhttps://foo.bar/image.jpg", "channel": "hash123", }, - SendPrep: setSendURL}, - {Label: "Invalid JSON", - MsgText: "Invalid XML", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `not json`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Error Response", - MsgText: "Error Response", MsgURN: "tel:+250788383383", - ExpectedStatus: "F", - MockResponseBody: `{"result":{}, "error_code": "10", "error_desc": "Failed"}`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `Bad Gateway`, MockResponseStatus: 501, - SendPrep: setSendURL}, + ExpectedStatus: "W", + ExpectedExternalID: "5b8fc97d58795484819426", + SendPrep: setSendURL, + }, + { + Label: "Invalid JSON", + MsgText: "Invalid XML", + MsgURN: "tel:+250788383383", + MockResponseBody: `not json`, + MockResponseStatus: 200, + ExpectedStatus: "E", + ExpectedErrors: []string{"invalid character 'o' in literal null (expecting 'u')"}, + SendPrep: setSendURL, + }, + { + Label: "Error Response", + MsgText: "Error Response", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"result":{}, "error_code": "10", "error_desc": "Failed"}`, + MockResponseStatus: 200, + ExpectedStatus: "F", + ExpectedErrors: []string{"Received invalid response code: 10"}, + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `Bad Gateway`, + MockResponseStatus: 501, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/infobip/infobip_test.go b/handlers/infobip/infobip_test.go index 4168a3195..fa61f9495 100644 --- a/handlers/infobip/infobip_test.go +++ b/handlers/infobip/infobip_test.go @@ -220,75 +220,103 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", ExpectedExternalID: "12345", - MockResponseBody: `{"messages":[{"status":{"groupId": 1}, "messageId": "12345"}}`, MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + ExpectedStatus: "W", + ExpectedExternalID: "12345", + MockResponseBody: `{"messages":[{"status":{"groupId": 1}, "messageId": "12345"}}`, + MockResponseStatus: 200, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Simple Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: "☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: `{"messages":[{"status":{"groupId": 1}}}`, MockResponseStatus: 200, + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"messages":[{"status":{"groupId": 1}}}`, + MockResponseStatus: 200, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"☺","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: `{"messages":[{"status":{"groupId": 1}}}`, MockResponseStatus: 200, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{"messages":[{"status":{"groupId": 1}}}`, + MockResponseStatus: 200, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"My pic!\nhttps://foo.bar/image.jpg","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "error": "failed" }`, + MockResponseStatus: 401, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Error Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, - SendPrep: setSendURL}, - {Label: "Error groupId", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `{"messages":[{"status":{"groupId": 2}}}`, MockResponseStatus: 200, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error groupId", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"messages":[{"status":{"groupId": 2}}}`, + MockResponseStatus: 200, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Simple Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, - SendPrep: setSendURL}, + ExpectedStatus: "E", + ExpectedErrors: []string{"received error status: '2'"}, + SendPrep: setSendURL, + }, } var transSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", ExpectedExternalID: "12345", - MockResponseBody: `{"messages":[{"status":{"groupId": 1}, "messageId": "12345"}}`, MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"messages":[{"status":{"groupId": 1}, "messageId": "12345"}}`, + MockResponseStatus: 200, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Simple Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered","transliteration":"COLOMBIAN"}]}`, - SendPrep: setSendURL}, + ExpectedStatus: "W", + ExpectedExternalID: "12345", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index 1f2528aa3..1b0f5bc0d 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -370,7 +370,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "jiochat:12345", ExpectedStatus: "E", MockResponseStatus: 401, - ExpectedError: "received non 200 status: 401", + ExpectedErrors: []string{"received non 200 status: 401"}, SendPrep: setSendURL}, } diff --git a/handlers/junebug/junebug_test.go b/handlers/junebug/junebug_test.go index 6c7f670dd..438e4eeaa 100644 --- a/handlers/junebug/junebug_test.go +++ b/handlers/junebug/junebug_test.go @@ -147,56 +147,73 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var sendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", + { + Label: "Plain Send", MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - ExpectedExternalID: "externalID", - ExpectedHeaders: map[string]string{"Authorization": "Basic dXNlcjE6cGFzczE="}, - ExpectedRequestBody: `{"event_url":"https://localhost/c/jn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/event","content":"Simple Message","from":"2020","to":"+250788383383"}`, MockResponseBody: `{"result":{"message_id":"externalID"}}`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Send Attachement", + ExpectedHeaders: map[string]string{"Authorization": "Basic dXNlcjE6cGFzczE="}, + ExpectedRequestBody: `{"event_url":"https://localhost/c/jn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/event","content":"Simple Message","from":"2020","to":"+250788383383"}`, + ExpectedStatus: "W", + ExpectedExternalID: "externalID", + SendPrep: setSendURL, + }, + { + Label: "Send Attachement", MsgText: "My pic!", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - ExpectedExternalID: "externalID", - ExpectedRequestBody: `{"event_url":"https://localhost/c/jn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/event","content":"My pic!\nhttps://foo.bar/image.jpg","from":"2020","to":"+250788383383"}`, MockResponseBody: `{"result":{"message_id":"externalID"}}`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Invalid JSON Response", - MsgText: "Error Sending", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", + ExpectedRequestBody: `{"event_url":"https://localhost/c/jn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/event","content":"My pic!\nhttps://foo.bar/image.jpg","from":"2020","to":"+250788383383"}`, + ExpectedStatus: "W", + ExpectedExternalID: "externalID", + SendPrep: setSendURL, + }, + { + Label: "Invalid JSON Response", + MsgText: "Error Sending", + MsgURN: "tel:+250788383383", MockResponseStatus: 200, MockResponseBody: "not json", - SendPrep: setSendURL}, - {Label: "Missing External ID", - MsgText: "Error Sending", MsgURN: "tel:+250788383383", ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get result.message_id from body"}, + SendPrep: setSendURL, + }, + { + Label: "Missing External ID", + MsgText: "Error Sending", + MsgURN: "tel:+250788383383", MockResponseStatus: 200, MockResponseBody: "{}", - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Sending", MsgURN: "tel:+250788383383", ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get result.message_id from body"}, + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Sending", + MsgURN: "tel:+250788383383", MockResponseStatus: 403, - SendPrep: setSendURL}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } var authenticatedSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", + { + Label: "Plain Send", MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - ExpectedExternalID: "externalID", - ExpectedHeaders: map[string]string{"Authorization": "Basic dXNlcjE6cGFzczE="}, - ExpectedRequestBody: `{"event_url":"https://localhost/c/jn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/event","content":"Simple Message","from":"2020","to":"+250788383383","event_auth_token":"sesame"}`, MockResponseBody: `{"result":{"message_id":"externalID"}}`, MockResponseStatus: 200, - SendPrep: setSendURL}, + ExpectedHeaders: map[string]string{"Authorization": "Basic dXNlcjE6cGFzczE="}, + ExpectedRequestBody: `{"event_url":"https://localhost/c/jn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/event","content":"Simple Message","from":"2020","to":"+250788383383","event_auth_token":"sesame"}`, + ExpectedStatus: "W", + ExpectedExternalID: "externalID", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/macrokiosk/macrokiosk_test.go b/handlers/macrokiosk/macrokiosk_test.go index bad397c85..e71cc2ab8 100644 --- a/handlers/macrokiosk/macrokiosk_test.go +++ b/handlers/macrokiosk/macrokiosk_test.go @@ -110,7 +110,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, - ExpectedError: "unable to parse response body from Macrokiosk", + ExpectedErrors: []string{"unable to parse response body from Macrokiosk"}, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", diff --git a/handlers/mblox/mblox_test.go b/handlers/mblox/mblox_test.go index 43b53c007..b9be3f89a 100644 --- a/handlers/mblox/mblox_test.go +++ b/handlers/mblox/mblox_test.go @@ -137,7 +137,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, - ExpectedError: "unable to parse response body from MBlox", + ExpectedErrors: []string{"unable to parse response body from MBlox"}, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", diff --git a/handlers/messangi/messangi_test.go b/handlers/messangi/messangi_test.go index f2967ecd4..b56438d9d 100644 --- a/handlers/messangi/messangi_test.go +++ b/handlers/messangi/messangi_test.go @@ -39,37 +39,53 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message ☺", MsgURN: "tel:+18765422035", - ExpectedStatus: "W", ExpectedExternalID: "", + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+18765422035", MockResponseBody: `sendMTOKCompleted`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Long Send", + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Long Send", MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", MsgURN: "tel:+18765422035", - ExpectedStatus: "W", - ExpectedExternalID: "", MockResponseBody: `sendMTOKCompleted`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+18765422035", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", ExpectedExternalID: "", + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+18765422035", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MockResponseBody: `sendMTOKCompleted`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Invalid Parameters", - MsgText: "Invalid Parameters", MsgURN: "tel:+18765422035", - ExpectedStatus: "E", - MockResponseBody: "", MockResponseStatus: 404, - SendPrep: setSendURL}, - {Label: "Error Response", - MsgText: "Error Response", MsgURN: "tel:+18765422035", - ExpectedStatus: "F", + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Invalid Parameters", + MsgText: "Invalid Parameters", + MsgURN: "tel:+18765422035", + MockResponseBody: "", + MockResponseStatus: 404, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error Response", + MsgText: "Error Response", + MsgURN: "tel:+18765422035", MockResponseBody: `sendMTERRORCompleted`, MockResponseStatus: 200, - SendPrep: setSendURL}, + ExpectedStatus: "F", + ExpectedErrors: []string{"Received invalid response description: Completed"}, + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/mtarget/mtarget_test.go b/handlers/mtarget/mtarget_test.go index 69a2388bf..4ccc45324 100644 --- a/handlers/mtarget/mtarget_test.go +++ b/handlers/mtarget/mtarget_test.go @@ -64,10 +64,12 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: `{"results":[{"code": "0", "ticket": "externalID"}]}`, MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"results":[{"code": "0", "ticket": "externalID"}]}`, + MockResponseStatus: 200, ExpectedURLParams: map[string]string{ "msisdn": "+250788383383", "msg": "Simple Message", @@ -76,29 +78,49 @@ var defaultSendTestCases = []ChannelSendTestCase{ "serviceid": "2020", "allowunicode": "true", }, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: "☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: `{"results":[{"code": "0", "ticket": "externalID"}]}`, MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"msg": "☺"}, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: `{"results":[{"code": "0", "ticket": "externalID"}]}`, MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"msg": "My pic!\nhttps://foo.bar/image.jpg"}, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Sending", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `{"results":[{"code": "3", "ticket": "null"}]}`, MockResponseStatus: 403, - SendPrep: setSendURL}, - {Label: "Error Response", - MsgText: "Error Sending", MsgURN: "tel:+250788383383", - ExpectedStatus: "F", - MockResponseBody: `{"results":[{"code": "3", "ticket": "null"}]}`, MockResponseStatus: 200, - SendPrep: setSendURL}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"results":[{"code": "0", "ticket": "externalID"}]}`, + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"msg": "☺"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{"results":[{"code": "0", "ticket": "externalID"}]}`, + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"msg": "My pic!\nhttps://foo.bar/image.jpg"}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Sending", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"results":[{"code": "3", "ticket": "null"}]}`, + MockResponseStatus: 403, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error Response", + MsgText: "Error Sending", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"results":[{"code": "3", "ticket": "null"}]}`, + MockResponseStatus: 200, + ExpectedStatus: "F", + ExpectedErrors: []string{"Error status code, failing permanently"}, + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/novo/novo_test.go b/handlers/novo/novo_test.go index 5795c6703..d75516796 100644 --- a/handlers/novo/novo_test.go +++ b/handlers/novo/novo_test.go @@ -46,38 +46,57 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message ☺", MsgURN: "tel:+18686846481", - ExpectedStatus: "W", ExpectedExternalID: "", + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+18686846481", MockResponseBody: `{"blastId": "-437733473338","status": "FINISHED","type": "SMS","statusDescription": "Finished"}`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Long Send", - MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - MsgURN: "tel:+18686846481", ExpectedStatus: "W", ExpectedExternalID: "", + SendPrep: setSendURL, + }, + { + Label: "Long Send", + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+18686846481", MockResponseBody: `{"blastId": "-437733473338","status": "FINISHED","type": "SMS","statusDescription": "Finished"}`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+18686846481", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", ExpectedExternalID: "", + ExpectedStatus: "W", + ExpectedExternalID: "", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+18686846481", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MockResponseBody: `{"blastId": "-437733473338","status": "FINISHED","type": "SMS","statusDescription": "Finished"}`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Invalid Parameters", - MsgText: "Invalid Parameters", MsgURN: "tel:+18686846481", - ExpectedStatus: "F", + ExpectedStatus: "W", + ExpectedExternalID: "", + SendPrep: setSendURL, + }, + { + Label: "Invalid Parameters", + MsgText: "Invalid Parameters", + MsgURN: "tel:+18686846481", MockResponseBody: `{"error": "Incorrect Query String Authentication ","expectedQueryString": "8868;18686846480;test;"}`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Error Response", - MsgText: "Error Response", MsgURN: "tel:+18686846481", ExpectedStatus: "F", + ExpectedErrors: []string{"received invalid response"}, + SendPrep: setSendURL, + }, + { + Label: "Error Response", + MsgText: "Error Response", + MsgURN: "tel:+18686846481", MockResponseBody: `{"error": "Incorrect Query String Authentication ","expectedQueryString": "8868;18686846480;test;"}`, MockResponseStatus: 200, - SendPrep: setSendURL}, + ExpectedStatus: "F", + ExpectedErrors: []string{"received invalid response"}, + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/plivo/plivo_test.go b/handlers/plivo/plivo_test.go index 3b879ef46..5d4257cc4 100644 --- a/handlers/plivo/plivo_test.go +++ b/handlers/plivo/plivo_test.go @@ -104,7 +104,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, - ExpectedError: "unable to parse response body from Plivo", + ExpectedErrors: []string{"unable to parse response body from Plivo"}, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", diff --git a/handlers/test.go b/handlers/test.go index 1916eea77..0a5c01c44 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -19,6 +19,7 @@ import ( "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/urns" "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -103,9 +104,9 @@ type ChannelSendTestCase struct { ExpectedRequestBody string ExpectedHeaders map[string]string - ExpectedError string ExpectedStatus string ExpectedExternalID string + ExpectedErrors []string ExpectedStopEvent bool ExpectedContactURNs map[string]bool @@ -272,16 +273,13 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour status, err := handler.Send(ctx, msg, logger) cancel() - if testCase.ExpectedError != "" { - if err == nil { - t.Errorf("expected error: %s", testCase.ExpectedError) - } else { - require.Equal(testCase.ExpectedError, err.Error()) - } - } else if err != nil { - t.Errorf("unexpected error: %s", err.Error()) + // we don't currently distinguish between a returned error and logged errors + if err != nil { + logger.Error(err) } + assert.Equal(t, testCase.ExpectedErrors, logger.Errors(), "unexpected errors logged") + if testCase.ExpectedRequestPath != "" { require.NotNil(testRequest, "path should not be nil") require.Equal(testCase.ExpectedRequestPath, testRequest.URL.Path) diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index a8719ecde..f7f2b55f9 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -160,7 +160,10 @@ var defaultSendTestCases = []ChannelSendTestCase{ } var invalidTokenSendTestCases = []ChannelSendTestCase{ - {Label: "Invalid token", ExpectedError: "missing auth token in config"}, + { + Label: "Invalid token", + ExpectedErrors: []string{"missing auth token in config"}, + }, } var buttonLayoutSendTestCases = []ChannelSendTestCase{ diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index e684b4ec9..e38019071 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -360,7 +360,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "wechat:12345", ExpectedStatus: "E", MockResponseStatus: 401, - ExpectedError: "received non 200 status: 401", + ExpectedErrors: []string{"received non 200 status: 401"}, SendPrep: setSendURL}, } diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index cd4658afe..e81e99c02 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -594,11 +594,11 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL, }, { - Label: "Template Invalid Language", - MsgText: "templated message", - MsgURN: "whatsapp:250788123123", - ExpectedError: `unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, - MsgMetadata: json.RawMessage(`{"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}}`), + Label: "Template Invalid Language", + MsgText: "templated message", + MsgURN: "whatsapp:250788123123", + ExpectedErrors: []string{`unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`}, + MsgMetadata: json.RawMessage(`{"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}}`), }, { Label: "WhatsApp Contact Error", diff --git a/handlers/zenvia/zenvia_test.go b/handlers/zenvia/zenvia_test.go index e57f54f86..3f34baf82 100644 --- a/handlers/zenvia/zenvia_test.go +++ b/handlers/zenvia/zenvia_test.go @@ -254,11 +254,10 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultWhatsappSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", + { + Label: "Plain Send", MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - ExpectedExternalID: "55555", MockResponseBody: `{"id": "55555"}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -267,12 +266,14 @@ var defaultWhatsappSendTestCases = []ChannelSendTestCase{ "X-API-TOKEN": "zv-api-token", }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"Simple Message ☺"}]}`, - SendPrep: setSendURL}, - {Label: "Long Send", + ExpectedStatus: "W", + ExpectedExternalID: "55555", + SendPrep: setSendURL, + }, + { + Label: "Long Send", MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - ExpectedExternalID: "55555", MockResponseBody: `{"id": "55555"}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -281,13 +282,15 @@ var defaultWhatsappSendTestCases = []ChannelSendTestCase{ "X-API-TOKEN": "zv-api-token", }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say,"},{"type":"text","text":"I need to keep adding more things to make it work"}]}`, - SendPrep: setSendURL}, - {Label: "Send Attachment", + ExpectedStatus: "W", + ExpectedExternalID: "55555", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - ExpectedExternalID: "55555", MockResponseBody: `{"id": "55555"}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -296,11 +299,14 @@ var defaultWhatsappSendTestCases = []ChannelSendTestCase{ "X-API-TOKEN": "zv-api-token", }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"file","fileUrl":"https://foo.bar/image.jpg","fileMimeType":"image/jpeg"},{"type":"text","text":"My pic!"}]}`, - SendPrep: setSendURL}, - {Label: "No External ID", + ExpectedStatus: "W", + ExpectedExternalID: "55555", + SendPrep: setSendURL, + }, + { + Label: "No External ID", MsgText: "No External ID", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", MockResponseBody: `{"code": "400","message": "Validation error","details": [{"code": "400","path": "Error","message": "Error description"}]}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -309,23 +315,27 @@ var defaultWhatsappSendTestCases = []ChannelSendTestCase{ "X-API-TOKEN": "zv-api-token", }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"No External ID"}]}`, - SendPrep: setSendURL}, - {Label: "Error Sending", + ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get id from body"}, + SendPrep: setSendURL, + }, + { + Label: "Error Sending", MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"Error Message"}]}`, - SendPrep: setSendURL}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } var defaultSMSSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", + { + Label: "Plain Send", MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - ExpectedExternalID: "55555", MockResponseBody: `{"id": "55555"}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -334,12 +344,13 @@ var defaultSMSSendTestCases = []ChannelSendTestCase{ "X-API-TOKEN": "zv-api-token", }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"Simple Message ☺"}]}`, + ExpectedStatus: "W", + ExpectedExternalID: "55555", SendPrep: setSendURL}, - {Label: "Long Send", + { + Label: "Long Send", MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - ExpectedExternalID: "55555", MockResponseBody: `{"id": "55555"}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -348,13 +359,14 @@ var defaultSMSSendTestCases = []ChannelSendTestCase{ "X-API-TOKEN": "zv-api-token", }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say,"},{"type":"text","text":"I need to keep adding more things to make it work"}]}`, + ExpectedStatus: "W", + ExpectedExternalID: "55555", SendPrep: setSendURL}, - {Label: "Send Attachment", + { + Label: "Send Attachment", MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - ExpectedExternalID: "55555", MockResponseBody: `{"id": "55555"}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -363,11 +375,14 @@ var defaultSMSSendTestCases = []ChannelSendTestCase{ "X-API-TOKEN": "zv-api-token", }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"My pic!\nhttps://foo.bar/image.jpg"}]}`, - SendPrep: setSendURL}, - {Label: "No External ID", + ExpectedStatus: "W", + ExpectedExternalID: "55555", + SendPrep: setSendURL, + }, + { + Label: "No External ID", MsgText: "No External ID", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", MockResponseBody: `{"code": "400","message": "Validation error","details": [{"code": "400","path": "Error","message": "Error description"}]}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -376,15 +391,20 @@ var defaultSMSSendTestCases = []ChannelSendTestCase{ "X-API-TOKEN": "zv-api-token", }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"No External ID"}]}`, - SendPrep: setSendURL}, - {Label: "Error Sending", + ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get id from body"}, + SendPrep: setSendURL, + }, + { + Label: "Error Sending", MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"Error Message"}]}`, - SendPrep: setSendURL}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/zenviaold/zenviaold_test.go b/handlers/zenviaold/zenviaold_test.go index 7541ba815..c9cd83565 100644 --- a/handlers/zenviaold/zenviaold_test.go +++ b/handlers/zenviaold/zenviaold_test.go @@ -136,11 +136,10 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", + { + Label: "Plain Send", MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - ExpectedExternalID: "", MockResponseBody: `{"sendSmsResponse":{"statusCode":"00","statusDescription":"Ok","detailCode":"000","detailDescription":"Message Sent"}}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -149,8 +148,12 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", }, ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"Simple Message ☺","callbackOption":"FINAL","id":"10","aggregateId":""}}`, - SendPrep: setSendURL}, - {Label: "Long Send", + ExpectedStatus: "W", + ExpectedExternalID: "", + SendPrep: setSendURL, + }, + { + Label: "Long Send", MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", MsgURN: "tel:+250788383383", ExpectedStatus: "W", @@ -163,13 +166,13 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", }, ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"I need to keep adding more things to make it work","callbackOption":"FINAL","id":"10","aggregateId":""}}`, - SendPrep: setSendURL}, - {Label: "Send Attachment", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - ExpectedExternalID: "", MockResponseBody: `{"sendSmsResponse":{"statusCode":"00","statusDescription":"Ok","detailCode":"000","detailDescription":"Message Sent"}}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -178,11 +181,14 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", }, ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"My pic!\nhttps://foo.bar/image.jpg","callbackOption":"FINAL","id":"10","aggregateId":""}}`, - SendPrep: setSendURL}, - {Label: "No External ID", + ExpectedStatus: "W", + ExpectedExternalID: "", + SendPrep: setSendURL, + }, + { + Label: "No External ID", MsgText: "No External ID", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", MockResponseBody: `{"sendSmsResponse" :{"statusCode" :"05","statusDescription" :"Blocked","detailCode":"140","detailDescription":"Mobile number not covered"}}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -191,15 +197,19 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", }, ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"No External ID","callbackOption":"FINAL","id":"10","aggregateId":""}}`, + ExpectedStatus: "E", + ExpectedErrors: []string{"received non-success response: '05'"}, SendPrep: setSendURL}, - {Label: "Error Sending", + { + Label: "Error Sending", MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"Error Message","callbackOption":"FINAL","id":"10","aggregateId":""}}`, - SendPrep: setSendURL}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { From fa125282995fdc275aebd0d3911654140303fc26 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 10 Aug 2022 17:48:31 -0500 Subject: [PATCH 060/294] More handlers to use new HTTP functions --- handlers/http.go | 15 +-- handlers/kannel/kannel.go | 13 +-- handlers/line/line.go | 18 ++-- handlers/plivo/plivo.go | 8 +- handlers/thinq/thinq.go | 25 ++--- handlers/thinq/thinq_test.go | 76 ++++++++++----- handlers/twitter/twitter.go | 132 +++++++++---------------- handlers/twitter/twitter_test.go | 162 ++++++++++++++++++------------- 8 files changed, 217 insertions(+), 232 deletions(-) diff --git a/handlers/http.go b/handlers/http.go index 6a46a6b65..9570e132e 100644 --- a/handlers/http.go +++ b/handlers/http.go @@ -38,20 +38,9 @@ func RequestHTTPWithClient(client *http.Client, req *http.Request, logger *couri return resp, body, nil } -// MakeHTTPRequest makes the given request and returns the trace +// Deprecated: use RequestHTTP instead func MakeHTTPRequest(req *http.Request) (*httpx.Trace, error) { - return MakeHTTPRequestWithClient(utils.GetHTTPClient(), req) -} - -// MakeInsecureHTTPRequest makes the given request using an insecure client that does not validate -// SSL certificates, and returns the trace -func MakeInsecureHTTPRequest(req *http.Request) (*httpx.Trace, error) { - return MakeHTTPRequestWithClient(utils.GetInsecureHTTPClient(), req) -} - -// MakeHTTPRequestWithClient makes the given request using the given client, and returns the trace -func MakeHTTPRequestWithClient(client *http.Client, req *http.Request) (*httpx.Trace, error) { - trace, err := httpx.DoTrace(client, req, nil, nil, 0) + trace, err := httpx.DoTrace(utils.GetHTTPClient(), req, nil, nil, 0) if err != nil { return trace, err } diff --git a/handlers/kannel/kannel.go b/handlers/kannel/kannel.go index 690d2a07d..60e6a36f5 100644 --- a/handlers/kannel/kannel.go +++ b/handlers/kannel/kannel.go @@ -11,7 +11,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/gocommon/gsm7" - "github.com/nyaruka/gocommon/httpx" ) const ( @@ -201,22 +200,20 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return nil, err } - var trace *httpx.Trace + var resp *http.Response if verifySSL { - trace, err = handlers.MakeHTTPRequest(req) + resp, _, err = handlers.RequestHTTP(req, logger) } else { - trace, err = handlers.MakeInsecureHTTPRequest(req) + resp, _, err = handlers.RequestHTTPInsecure(req, logger) } - // record our status and log status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - status.AddLog(courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err)) - if err == nil { + if err == nil && resp.StatusCode/100 == 2 { status.SetStatus(courier.MsgWired) } // kannel will respond with a 403 for non-routable numbers, fail permanently in these cases - if trace.Response != nil && trace.Response.StatusCode == 403 { + if resp != nil && resp.StatusCode == 403 { status.SetStatus(courier.MsgFailed) } diff --git a/handlers/line/line.go b/handlers/line/line.go index ba375f481..f7710743c 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -331,28 +331,24 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return status, err } - trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - - if err == nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err == nil && resp.StatusCode/100 == 2 { batch = []string{} batchCount = 0 continue } + // retry without the reply token if it's invalid - errMsg, err := jsonparser.GetString(trace.ResponseBody, "message") + errMsg, err := jsonparser.GetString(respBody, "message") if err == nil && errMsg == "Invalid reply token" { req, err = buildSendMsgRequest(authToken, msg.URN().Path(), "", batch) if err != nil { return status, err } - trace, err = handlers.MakeHTTPRequest(req) - log = courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { - return status, err + resp, _, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return status, nil } } else { return status, err diff --git a/handlers/plivo/plivo.go b/handlers/plivo/plivo.go index 16c033352..677abae18 100644 --- a/handlers/plivo/plivo.go +++ b/handlers/plivo/plivo.go @@ -170,14 +170,12 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.SetBasicAuth(authID, authToken) - trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - externalID, err := jsonparser.GetString(trace.ResponseBody, "message_uuid", "[0]") + externalID, err := jsonparser.GetString(respBody, "message_uuid", "[0]") if err != nil { return status, fmt.Errorf("unable to parse response body from Plivo") } diff --git a/handlers/thinq/thinq.go b/handlers/thinq/thinq.go index 597d750eb..f3e351ee6 100644 --- a/handlers/thinq/thinq.go +++ b/handlers/thinq/thinq.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "mime/multipart" "net/http" @@ -165,19 +166,15 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.SetBasicAuth(tokenUser, token) - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } // try to get our external id - externalID, err := jsonparser.GetString(trace.ResponseBody, "guid") + externalID, err := jsonparser.GetString(respBody, "guid") if err != nil { - log.WithError("Unable to read external ID", err) + logger.Error(errors.New("Unable to read external ID")) return status, nil } status.SetStatus(courier.MsgWired) @@ -202,19 +199,15 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.SetBasicAuth(tokenUser, token) - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } // get our external id - externalID, err := jsonparser.GetString(trace.ResponseBody, "guid") + externalID, err := jsonparser.GetString(respBody, "guid") if err != nil { - log.WithError("Unable to read external ID from guid field", err) + logger.Error(errors.New("Unable to read external ID from guid field")) return status, nil } diff --git a/handlers/thinq/thinq_test.go b/handlers/thinq/thinq_test.go index f3a80bb39..5595076f3 100644 --- a/handlers/thinq/thinq_test.go +++ b/handlers/thinq/thinq_test.go @@ -50,36 +50,62 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var sendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message ☺", MsgURN: "tel:+12067791234", - ExpectedStatus: "W", ExpectedExternalID: "1002", - MockResponseBody: `{ "guid": "1002" }`, MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+12067791234", + MockResponseBody: `{ "guid": "1002" }`, + MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "Basic dXNlcjE6c2VzYW1l"}, ExpectedRequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"Simple Message ☺"}`, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+12067791234", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", ExpectedExternalID: "1002", - MockResponseBody: `{ "guid": "1002" }`, MockResponseStatus: 200, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+12067791234", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{ "guid": "1002" }`, + MockResponseStatus: 200, ExpectedRequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"My pic!"}`, - SendPrep: setSendURL}, - {Label: "Only Attachment", - MsgText: "", MsgURN: "tel:+12067791234", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", ExpectedExternalID: "1002", - MockResponseBody: `{ "guid": "1002" }`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "No External ID", - MsgText: "No External ID", MsgURN: "tel:+12067791234", - ExpectedStatus: "E", - MockResponseBody: `{}`, MockResponseStatus: 200, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Only Attachment", + MsgText: "", + MsgURN: "tel:+12067791234", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{ "guid": "1002" }`, + MockResponseStatus: 200, + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "No External ID", + MsgText: "No External ID", + MsgURN: "tel:+12067791234", + MockResponseBody: `{}`, + MockResponseStatus: 200, ExpectedRequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"No External ID"}`, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+12067791234", - ExpectedStatus: "E", - MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, + ExpectedStatus: "E", + ExpectedErrors: []string{"Unable to read external ID from guid field"}, + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+12067791234", + MockResponseBody: `{ "error": "failed" }`, + MockResponseStatus: 401, ExpectedRequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"Error Message"}`, - SendPrep: setSendURL}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/twitter/twitter.go b/handlers/twitter/twitter.go index 2ffcb64e2..05574959e 100644 --- a/handlers/twitter/twitter.go +++ b/handlers/twitter/twitter.go @@ -270,7 +270,6 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha client := config.Client(ctx, token) status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - var logs []*courier.ChannelLog // we build these as needed since our unit tests manipulate apiURL sendURL := sendDomain + "/1.1/direct_messages/events/new.json" @@ -292,23 +291,16 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha // this is still a msg part payload.Event.MessageCreate.MessageData.Text = msgParts[i] } else { - start := time.Now() attachment := msg.Attachments()[i-len(msgParts)] mimeType, s3url := handlers.SplitAttachment(attachment) mediaID := "" if strings.HasPrefix(mimeType, "image") || strings.HasPrefix(mimeType, "video") { - mediaID, logs, err = uploadMediaToTwitter(msg, mediaURL, mimeType, s3url, client) + mediaID, err = uploadMediaToTwitter(msg, mediaURL, mimeType, s3url, client, logger) if err != nil { - duration := time.Now().Sub(start) - logs = append(logs, courier.NewChannelLogFromError("Unable to upload media to Twitter server", msg.Channel(), msg.ID(), duration, err)) + logger.Error(errors.Wrap(err, "unable to upload media to Twitter server")) } - for _, log := range logs { - status.AddLog(log) - } - } else { - duration := time.Now().Sub(start) - status.AddLog(courier.NewChannelLogFromError("Unable to upload media, Unsupported Twitter attachment", msg.Channel(), msg.ID(), duration, fmt.Errorf("unknown attachment type"))) + logger.Error(errors.New("unable to upload media, unsupported Twitter attachment")) } if mediaID != "" { @@ -345,18 +337,15 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req, _ := http.NewRequest(http.MethodPost, sendURL, bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequestWithClient(client, req) - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTPWithClient(client, req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - externalID, err := jsonparser.GetString(trace.ResponseBody, "event", "id") + externalID, err := jsonparser.GetString(respBody, "event", "id") if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to get message_id from body")) + logger.Error(errors.Errorf("unable to get message_id from body")) return status, nil } @@ -381,20 +370,14 @@ func generateSignature(secret string, content string) string { return base64.StdEncoding.EncodeToString(h.Sum(nil)) } -func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType string, attachmentURL string, client *http.Client) (string, []*courier.ChannelLog, error) { - start := time.Now() - logs := make([]*courier.ChannelLog, 0, 1) - +func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType string, attachmentURL string, client *http.Client, logger *courier.ChannelLogger) (string, error) { // retrieve the media to be sent from S3 req, _ := http.NewRequest(http.MethodGet, attachmentURL, nil) - s3Trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromTrace("Media Fetch", msg.Channel(), msg.ID(), s3Trace) - if err != nil { - log.WithError("Media Fetch Error", err) - logs = append(logs, log) - return "", logs, err + + s3Resp, s3RespBody, err := handlers.RequestHTTP(req, logger) + if err != nil || s3Resp.StatusCode/100 != 2 { + return "", err } - logs = append(logs, log) mediaCategory := "" if strings.HasPrefix(attachmentMimeType, "image") { @@ -403,7 +386,7 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s mediaCategory = "dm_video" } - fileSize := int64(len(s3Trace.ResponseBody)) + fileSize := int64(len(s3RespBody)) // upload it to WhatsApp in exchange for a media id form := url.Values{ @@ -421,21 +404,16 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s twReq.Header.Set("Accept", "application/json") twReq.Header.Set("User-Agent", utils.HTTPUserAgent) - twTrace, err := handlers.MakeHTTPRequestWithClient(client, twReq) - log = courier.NewChannelLogFromTrace("Media Upload INIT", msg.Channel(), msg.ID(), twTrace) - if err != nil { - log.WithError("Media Upload INIT Error", err) - logs = append(logs, log) - return "", logs, err + twResp, twRespBody, err := handlers.RequestHTTPWithClient(client, twReq, logger) + if err != nil || twResp.StatusCode/100 != 2 { + return "", err } - logs = append(logs, log) - mediaID, err := jsonparser.GetString(twTrace.ResponseBody, "media_id_string") + mediaID, err := jsonparser.GetString(twRespBody, "media_id_string") if err != nil { - duration := time.Now().Sub(start) - logs = append(logs, courier.NewChannelLogFromError("Media Upload media_id Error", msg.Channel(), msg.ID(), duration, err)) - return "", logs, err + return "", err } + tokens := strings.Split(attachmentURL, "/") fileName := tokens[len(tokens)-1] @@ -447,25 +425,18 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s for k, v := range params { fieldWriter, err := bodyMultipartWriter.CreateFormField(k) if err != nil { - duration := time.Now().Sub(start) - logs = append(logs, courier.NewChannelLogFromError(fmt.Sprintf("Media Upload APPEND field %s Error", k), msg.Channel(), msg.ID(), duration, err)) - return "", logs, err + return "", err } _, err = fieldWriter.Write([]byte(v)) if err != nil { - duration := time.Now().Sub(start) - logs = append(logs, courier.NewChannelLogFromError(fmt.Sprintf("Media Upload APPEND field %s Error", k), msg.Channel(), msg.ID(), duration, err)) - return "", logs, err + return "", err } - } mediaWriter, err := bodyMultipartWriter.CreateFormFile("media", fileName) - _, err = io.Copy(mediaWriter, bytes.NewReader(s3Trace.ResponseBody)) + _, err = io.Copy(mediaWriter, bytes.NewReader(s3RespBody)) if err != nil { - duration := time.Now().Sub(start) - logs = append(logs, courier.NewChannelLogFromError("Media Upload APPEND field media Error", msg.Channel(), msg.ID(), duration, err)) - return "", logs, err + return "", err } contentType := fmt.Sprintf("multipart/form-data;boundary=%v", bodyMultipartWriter.Boundary()) @@ -475,14 +446,12 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s twReq.Header.Set("Content-Type", contentType) twReq.Header.Set("Accept", "application/json") twReq.Header.Set("User-Agent", utils.HTTPUserAgent) - twTrace, err = handlers.MakeHTTPRequestWithClient(client, twReq) - log = courier.NewChannelLogFromTrace("Media Upload APPEND request", msg.Channel(), msg.ID(), twTrace) - if err != nil { - log = log.WithError("Media Upload APPEND request Error", err) - logs = append(logs, log) - return "", logs, err + + twResp, twRespBody, err = handlers.RequestHTTPWithClient(client, twReq, logger) + if err != nil || twResp.StatusCode/100 != 2 { + return "", err } - logs = append(logs, log) + form = url.Values{ "command": []string{"FINALIZE"}, "media_id": []string{mediaID}, @@ -490,32 +459,27 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s twReq, err = http.NewRequest(http.MethodPost, mediaUrl, strings.NewReader(form.Encode())) if err != nil { - return "", nil, err + return "", err } + twReq.Header.Set("Content-Type", "application/x-www-form-urlencoded") twReq.Header.Set("Accept", "application/json") twReq.Header.Set("User-Agent", utils.HTTPUserAgent) - twTrace, err = handlers.MakeHTTPRequestWithClient(client, twReq) - log = courier.NewChannelLogFromTrace("Media Upload FINALIZE", msg.Channel(), msg.ID(), twTrace) - - if err != nil { - log.WithError("Media Upload FINALIZE Error", err) - logs = append(logs, log) - return "", logs, err + twResp, twRespBody, err = handlers.RequestHTTPWithClient(client, twReq, logger) + if err != nil || twResp.StatusCode/100 != 2 { + return "", err } - logs = append(logs, log) - progressState, err := jsonparser.GetString(twTrace.ResponseBody, "processing_info", "state") + progressState, err := jsonparser.GetString(twRespBody, "processing_info", "state") if err != nil { - return mediaID, logs, nil + return mediaID, nil } for { - - checkAfter, err := jsonparser.GetInt(twTrace.ResponseBody, "processing_info", "check_after_secs") + checkAfter, err := jsonparser.GetInt(twRespBody, "processing_info", "check_after_secs") if err != nil { - return "", logs, err + return "", err } time.Sleep(time.Duration(checkAfter * int64(time.Second))) @@ -533,30 +497,22 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s twReq.Header.Set("Accept", "application/json") twReq.Header.Set("User-Agent", utils.HTTPUserAgent) - twTrace, err = handlers.MakeHTTPRequestWithClient(client, twReq) - log = courier.NewChannelLogFromTrace("Media Upload STATUS", msg.Channel(), msg.ID(), twTrace) - if err != nil { - log.WithError("Media Upload STATUS Error", err) - logs = append(logs, log) - return "", logs, err + twResp, twRespBody, err = handlers.RequestHTTPWithClient(client, twReq, logger) + if err != nil || twResp.StatusCode/100 != 2 { + return "", err } - progressState, err = jsonparser.GetString(twTrace.ResponseBody, "processing_info", "state") + + progressState, err = jsonparser.GetString(twRespBody, "processing_info", "state") if err != nil { - log.WithError("Media Upload STATUS failed parse JSON", err) - logs = append(logs, log) break } if progressState == "succeeded" { - logs = append(logs, log) break } if progressState == "failed" { - logs = append(logs, log) - return "", logs, err + return "", err } - logs = append(logs, log) - } - return mediaID, logs, nil + return mediaID, nil } diff --git a/handlers/twitter/twitter_test.go b/handlers/twitter/twitter_test.go index a58854a02..676c0d34b 100644 --- a/handlers/twitter/twitter_test.go +++ b/handlers/twitter/twitter_test.go @@ -194,168 +194,183 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "twitterid:12345", - ExpectedStatus: "W", ExpectedExternalID: "133", + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "twitterid:12345", + MockResponseBody: `{"event": { "id": "133"}}`, + MockResponseStatus: 200, ExpectedRequestPath: "/1.1/direct_messages/events/new.json", - MockResponseBody: `{"event": { "id": "133"}}`, MockResponseStatus: 200, ExpectedRequestBody: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"Simple Message"}}}}`, - SendPrep: setSendURL}, - {Label: "Quick Reply", - MsgText: "Are you happy?", MsgURN: "twitterid:12345", MsgQuickReplies: []string{"Yes", "No, but a really long no that is unreasonably long"}, - ExpectedStatus: "W", ExpectedExternalID: "133", - MockResponseBody: `{"event": { "id": "133"}}`, MockResponseStatus: 200, + ExpectedStatus: "W", + ExpectedExternalID: "133", + SendPrep: setSendURL, + }, + { + Label: "Quick Reply", + MsgText: "Are you happy?", + MsgURN: "twitterid:12345", + MsgQuickReplies: []string{"Yes", "No, but a really long no that is unreasonably long"}, + MockResponseBody: `{"event": { "id": "133"}}`, + MockResponseStatus: 200, ExpectedRequestBody: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"Are you happy?","quick_reply":{"type":"options","options":[{"label":"Yes"},{"label":"No, but a really long no that is unr"}]}}}}}`, - SendPrep: setSendURL}, - {Label: "Image Send", + ExpectedStatus: "W", + ExpectedExternalID: "133", + SendPrep: setSendURL, + }, + { + Label: "Image Send", MsgText: "document caption", MsgURN: "twitterid:12345", - ExpectedStatus: "W", ExpectedExternalID: "133", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MockResponses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { Method: "POST", Path: "/1.1/media/upload.json", Body: `command=INIT&media_category=dm_image&media_type=image%2Fjpeg&total_bytes=10`, - }: MockedResponse{ + }: { Status: 200, Body: `{ "media_id": 710511363345354753, "media_id_string": "710511363345354753", }`, }, - MockedRequest{ + { Method: "POST", Path: "/1.1/media/upload.json", BodyContains: "APPEND", - }: MockedResponse{ + }: { Status: 200, Body: `{ "media_id": 710511363345354753, "media_id_string": "710511363345354753", }`, }, - MockedRequest{ + { Method: "POST", Path: "/1.1/media/upload.json", Body: `command=FINALIZE&media_id=710511363345354753`, - }: MockedResponse{ + }: { Status: 200, Body: `{ "media_id": 710511363345354753, "media_id_string": "710511363345354753", }`, }, - MockedRequest{ + { Method: "POST", Path: "/1.1/direct_messages/events/new.json", Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"document caption"}}}}`, - }: MockedResponse{ + }: { Status: 200, Body: `{"event": { "id": "133"}}`, }, - MockedRequest{ + { Method: "POST", Path: "/1.1/direct_messages/events/new.json", Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"","attachment":{"type":"media","media":{"id":"710511363345354753"}}}}}}`, - }: MockedResponse{ + }: { Status: 200, Body: `{"event": { "id": "133"}}`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "133", + SendPrep: setSendURL, }, - {Label: "Image Send", + { + Label: "Image Send", MsgText: "document caption", MsgURN: "twitterid:12345", - ExpectedStatus: "W", ExpectedExternalID: "133", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MockResponses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { Method: "POST", Path: "/1.1/media/upload.json", Body: `command=INIT&media_category=dm_image&media_type=image%2Fjpeg&total_bytes=10`, - }: MockedResponse{ + }: { Status: 200, Body: `{ "media_id": 710511363345354753, "media_id_string": "710511363345354753", }`, }, - MockedRequest{ + { Method: "POST", Path: "/1.1/media/upload.json", BodyContains: "APPEND", - }: MockedResponse{ + }: { Status: 200, Body: `{ "media_id": 710511363345354753, "media_id_string": "710511363345354753", }`, }, - MockedRequest{ + { Method: "POST", Path: "/1.1/media/upload.json", Body: `command=FINALIZE&media_id=710511363345354753`, - }: MockedResponse{ + }: { Status: 200, Body: `{ "media_id": 710511363345354753, "media_id_string": "710511363345354753", }`, }, - MockedRequest{ + { Method: "POST", Path: "/1.1/direct_messages/events/new.json", Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"document caption"}}}}`, - }: MockedResponse{ + }: { Status: 200, Body: `{"event": { "id": "133"}}`, }, - MockedRequest{ + { Method: "POST", Path: "/1.1/direct_messages/events/new.json", Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"","attachment":{"type":"media","media":{"id":"710511363345354753"}}}}}}`, - }: MockedResponse{ + }: { Status: 200, Body: `{"event": { "id": "133"}}`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "133", + SendPrep: setSendURL, }, - {Label: "Video Send", + { + Label: "Video Send", MsgText: "document caption", MsgURN: "twitterid:12345", - ExpectedStatus: "W", ExpectedExternalID: "133", MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, MockResponses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { Method: "POST", Path: "/1.1/media/upload.json", Body: `command=INIT&media_category=dm_video&media_type=video%2Fmp4&total_bytes=10`, - }: MockedResponse{ + }: { Status: 200, Body: `{ "media_id": 710511363345354753, "media_id_string": "710511363345354753", }`, }, - MockedRequest{ + { Method: "POST", Path: "/1.1/media/upload.json", BodyContains: "APPEND", - }: MockedResponse{ + }: { Status: 200, Body: `{ "media_id": 710511363345354753, "media_id_string": "710511363345354753", }`, }, - MockedRequest{ + { Method: "POST", Path: "/1.1/media/upload.json", Body: `command=FINALIZE&media_id=710511363345354753`, - }: MockedResponse{ + }: { Status: 200, Body: `{ "media_id": 710511363345354753, @@ -363,59 +378,74 @@ var defaultSendTestCases = []ChannelSendTestCase{ "processing_info" : {"state": "pending", "check_after_secs": 2}, }`, }, - MockedRequest{ + { Method: "POST", Path: "/1.1/direct_messages/events/new.json", Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"document caption"}}}}`, - }: MockedResponse{ + }: { Status: 200, Body: `{"event": { "id": "133"}}`, }, - MockedRequest{ + { Method: "POST", Path: "/1.1/direct_messages/events/new.json", Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"","attachment":{"type":"media","media":{"id":"710511363345354753"}}}}}}`, - }: MockedResponse{ + }: { Status: 200, Body: `{"event": { "id": "133"}}`, }, }, - SendPrep: setSendURL, + ExpectedStatus: "W", + ExpectedExternalID: "133", + SendPrep: setSendURL, }, - {Label: "Send Audio", + { + Label: "Send Audio", MsgText: "My audio!", MsgURN: "twitterid:12345", - ExpectedStatus: "W", ExpectedExternalID: "133", MsgAttachments: []string{"audio/mp3:https://foo.bar/audio.mp3"}, MockResponses: map[MockedRequest]MockedResponse{ - MockedRequest{ + { Method: "POST", Path: "/1.1/direct_messages/events/new.json", Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"My audio!"}}}}`, - }: MockedResponse{ + }: { Status: 200, Body: `{"event": { "id": "133"}}`, }, - MockedRequest{ + { Method: "POST", Path: "/1.1/direct_messages/events/new.json", BodyContains: `"text":"http`, // audio link send as text - }: MockedResponse{ + }: { Status: 200, Body: `{"event": { "id": "133"}}`, }, }, - SendPrep: setSendURL}, - {Label: "ID Error", - MsgText: "ID Error", MsgURN: "twitterid:12345", - ExpectedStatus: "E", - MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Error", - MsgText: "Error", MsgURN: "twitterid:12345", - ExpectedStatus: "E", - MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 403, - SendPrep: setSendURL}, + ExpectedStatus: "W", + ExpectedExternalID: "133", + ExpectedErrors: []string{"unable to upload media, unsupported Twitter attachment"}, + SendPrep: setSendURL, + }, + { + Label: "ID Error", + MsgText: "ID Error", + MsgURN: "twitterid:12345", + MockResponseBody: `{ "is_error": true }`, + MockResponseStatus: 200, + ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get message_id from body"}, + SendPrep: setSendURL, + }, + { + Label: "Error", + MsgText: "Error", + MsgURN: "twitterid:12345", + MockResponseBody: `{ "is_error": true }`, + MockResponseStatus: 403, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } func mockAttachmentURLs(mediaServer *httptest.Server, testCases []ChannelSendTestCase) []ChannelSendTestCase { From 6d242a8b05db8cb37473e99f720a6a9eb8a26c69 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 10 Aug 2022 18:31:46 -0500 Subject: [PATCH 061/294] Rename fields on ChannelHandleTestCase for clarity --- .../africastalking/africastalking_test.go | 106 +++++++--- handlers/arabiacell/arabiacell_test.go | 6 +- handlers/blackmyna/blackmyna_test.go | 16 +- handlers/bongolive/bongolive_test.go | 18 +- handlers/burstsms/burstsms_test.go | 12 +- handlers/chikka/chikka_test.go | 20 +- handlers/clickatell/clickatell_test.go | 34 ++-- handlers/clickmobile/clickmobile_test.go | 24 +-- handlers/clicksend/clicksend_test.go | 4 +- handlers/dart/dart_test.go | 18 +- handlers/discord/discord_test.go | 14 +- handlers/dmark/dmark_test.go | 20 +- handlers/external/external_test.go | 74 +++---- handlers/facebook/facebook_test.go | 76 +++---- handlers/facebookapp/facebookapp_test.go | 190 +++++++++--------- handlers/firebase/firebase_test.go | 12 +- handlers/freshchat/freshchat_test.go | 16 +- handlers/globe/globe_test.go | 14 +- .../highconnection/highconnection_test.go | 22 +- handlers/hormuud/hormuud_test.go | 12 +- handlers/i2sms/i2sms_test.go | 6 +- handlers/infobip/infobip_test.go | 26 +-- handlers/jasmin/jasmin_test.go | 28 +-- handlers/jiochat/jiochat_test.go | 36 ++-- handlers/junebug/junebug_test.go | 50 ++--- handlers/kaleyra/kaleyra_test.go | 110 +++++----- handlers/kannel/kannel_test.go | 32 +-- handlers/line/line_test.go | 36 ++-- handlers/m3tech/m3tech_test.go | 8 +- handlers/macrokiosk/macrokiosk_test.go | 32 +-- handlers/mblox/mblox_test.go | 16 +- handlers/messangi/messangi_test.go | 6 +- handlers/mtarget/mtarget_test.go | 32 +-- handlers/nexmo/nexmo_test.go | 26 +-- handlers/novo/novo_test.go | 10 +- handlers/playmobile/playmobile_test.go | 56 +++--- handlers/plivo/plivo_test.go | 18 +- handlers/rocketchat/rocketchat_test.go | 32 +-- handlers/shaqodoon/shaqodoon_test.go | 28 +-- handlers/slack/slack_test.go | 87 ++++---- handlers/smscentral/smscentral_test.go | 14 +- handlers/start/start_test.go | 26 +-- handlers/telegram/telegram_test.go | 62 +++--- handlers/telesom/telesom_test.go | 20 +- handlers/test.go | 184 ++++++++--------- handlers/thinq/thinq_test.go | 22 +- handlers/twiml/twiml_test.go | 180 ++++++++--------- handlers/twitter/twitter_test.go | 20 +- handlers/viber/viber_test.go | 66 +++--- handlers/vk/vk_test.go | 174 ++++++++-------- handlers/wavy/wavy_test.go | 28 +-- handlers/wechat/wechat_test.go | 34 ++-- handlers/whatsapp/whatsapp_test.go | 60 +++--- handlers/yo/yo_test.go | 24 +-- handlers/zenvia/zenvia_test.go | 56 +++--- handlers/zenviaold/zenviaold_test.go | 30 +-- 56 files changed, 1215 insertions(+), 1168 deletions(-) diff --git a/handlers/africastalking/africastalking_test.go b/handlers/africastalking/africastalking_test.go index 1f9537fbe..41d6f7dd2 100644 --- a/handlers/africastalking/africastalking_test.go +++ b/handlers/africastalking/africastalking_test.go @@ -14,38 +14,90 @@ var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AT", "2020", "US", nil), } -var ( +const ( receiveURL = "/c/at/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" statusURL = "/c/at/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/" - - emptyReceive = "empty" - validReceive = "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=%2B254791541111" - validOtherDateReceive = "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03+06%3A04%3A45&from=%2B254791541111" - invalidURN = "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=MTN" - missingText = "linkId=03090445075804249226&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=%2B254791541111" - invalidDate = "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04&from=%2B254791541111" - - missingStatus = "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7" - invalidStatus = "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Borked" - successStatus = "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Success" - expiredStatus = "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Expired" ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Msg"), URN: Sp("tel:+254791541111"), ExternalID: Sp("ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3"), - Date: Tp(time.Date(2017, 5, 3, 06, 04, 45, 0, time.UTC))}, - {Label: "Receive Valid", URL: receiveURL, Data: validOtherDateReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Msg"), URN: Sp("tel:+254791541111"), ExternalID: Sp("ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3"), - Date: Tp(time.Date(2017, 5, 3, 06, 04, 45, 0, time.UTC))}, - {Label: "Receive Empty", URL: receiveURL, Data: emptyReceive, Status: 400, Response: "field 'id' required"}, - {Label: "Receive Missing Text", URL: receiveURL, Data: missingText, Status: 400, Response: "field 'text' required"}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Invalid Date", URL: receiveURL, Data: invalidDate, Status: 400, Response: "invalid date format"}, - {Label: "Status Invalid", URL: statusURL, Status: 400, Data: invalidStatus, Response: "unknown status"}, - {Label: "Status Missing", URL: statusURL, Status: 400, Data: missingStatus, Response: "field 'status' required"}, - {Label: "Status Success", URL: statusURL, Status: 200, Data: successStatus, Response: `"status":"D"`}, - {Label: "Status Expired", URL: statusURL, Status: 200, Data: expiredStatus, Response: `"status":"F"`}, + { + Label: "Receive Valid", + URL: receiveURL, + Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=%2B254791541111", + ExpectedStatus: 200, + ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: Sp("tel:+254791541111"), + ExpectedExternalID: Sp("ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3"), + ExpectedDate: Tp(time.Date(2017, 5, 3, 06, 04, 45, 0, time.UTC)), + }, + { + Label: "Receive Valid", + URL: receiveURL, + Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03+06%3A04%3A45&from=%2B254791541111", + ExpectedStatus: 200, + ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: Sp("tel:+254791541111"), + ExpectedExternalID: Sp("ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3"), + ExpectedDate: Tp(time.Date(2017, 5, 3, 06, 04, 45, 0, time.UTC)), + }, + { + Label: "Receive Empty", + URL: receiveURL, + Data: "empty", + ExpectedStatus: 400, + ExpectedResponse: "field 'id' required", + }, + { + Label: "Receive Missing Text", + URL: receiveURL, + Data: "linkId=03090445075804249226&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=%2B254791541111", + ExpectedStatus: 400, + ExpectedResponse: "field 'text' required", + }, + { + Label: "Invalid URN", + URL: receiveURL, + Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=MTN", + ExpectedStatus: 400, + ExpectedResponse: "phone number supplied is not a number", + }, + { + Label: "Invalid Date", + URL: receiveURL, + Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04&from=%2B254791541111", + ExpectedStatus: 400, + ExpectedResponse: "invalid date format", + }, + { + Label: "Status Invalid", + URL: statusURL, + ExpectedStatus: 400, + Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Borked", + ExpectedResponse: "unknown status", + }, + { + Label: "Status Missing", + URL: statusURL, + ExpectedStatus: 400, + Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7", + ExpectedResponse: "field 'status' required", + }, + { + Label: "Status Success", + URL: statusURL, + ExpectedStatus: 200, + Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Success", + ExpectedResponse: `"status":"D"`, + }, + { + Label: "Status Expired", + URL: statusURL, + ExpectedStatus: 200, + Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Expired", + ExpectedResponse: `"status":"F"`, + }, } func TestHandler(t *testing.T) { diff --git a/handlers/arabiacell/arabiacell_test.go b/handlers/arabiacell/arabiacell_test.go index 4e9aa1914..3400cac75 100644 --- a/handlers/arabiacell/arabiacell_test.go +++ b/handlers/arabiacell/arabiacell_test.go @@ -21,9 +21,9 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Msg"), URN: Sp("tel:+254791541111")}, - {Label: "Receive Missing Number", URL: receiveURL, Data: missingNumber, Status: 400, Response: "required field 'M'"}, + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111")}, + {Label: "Receive Missing Number", URL: receiveURL, Data: missingNumber, ExpectedStatus: 400, ExpectedResponse: "required field 'M'"}, } func TestHandler(t *testing.T) { diff --git a/handlers/blackmyna/blackmyna_test.go b/handlers/blackmyna/blackmyna_test.go index 5ad017704..1370c781a 100644 --- a/handlers/blackmyna/blackmyna_test.go +++ b/handlers/blackmyna/blackmyna_test.go @@ -28,15 +28,15 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: validReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Msg"), URN: Sp("tel:+9779814641111")}, - {Label: "Invalid URN", URL: invalidURN, Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Receive Empty", URL: emptyReceive, Status: 400, Response: "field 'text' required"}, - {Label: "Receive Missing Text", URL: missingText, Status: 400, Response: "field 'text' required"}, + {Label: "Receive Valid", URL: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+9779814641111")}, + {Label: "Invalid URN", URL: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Receive Empty", URL: emptyReceive, ExpectedStatus: 400, ExpectedResponse: "field 'text' required"}, + {Label: "Receive Missing Text", URL: missingText, ExpectedStatus: 400, ExpectedResponse: "field 'text' required"}, - {Label: "Status Invalid", URL: invalidStatus, Status: 400, Response: "unknown status"}, - {Label: "Status Missing", URL: missingStatus, Status: 400, Response: "field 'status' required"}, - {Label: "Valid Status", URL: validStatus, Status: 200, Response: `"status":"F"`}, + {Label: "Status Invalid", URL: invalidStatus, ExpectedStatus: 400, ExpectedResponse: "unknown status"}, + {Label: "Status Missing", URL: missingStatus, ExpectedStatus: 400, ExpectedResponse: "field 'status' required"}, + {Label: "Valid Status", URL: validStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`}, } func TestHandler(t *testing.T) { diff --git a/handlers/bongolive/bongolive_test.go b/handlers/bongolive/bongolive_test.go index 0863c86b4..6cb0c39c3 100644 --- a/handlers/bongolive/bongolive_test.go +++ b/handlers/bongolive/bongolive_test.go @@ -27,15 +27,15 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, Status: 200, Response: "", - Text: Sp("Msg"), URN: Sp("tel:+254791541111")}, - {Label: "Receive Valid", URL: receiveURL, Data: validReceiveNoMsgType, Status: 200, Response: "", - Text: Sp("Msg"), URN: Sp("tel:+254791541111")}, - {Label: "Receive Missing Number", URL: receiveURL, Data: missingNumber, Status: 400, Response: ""}, - {Label: "Status No params", URL: receiveURL, Data: "", Status: 405, Response: ""}, - {Label: "Status invalid params", URL: receiveURL, Data: invalidStatus, Status: 400, Response: ""}, - {Label: "Status valid", URL: receiveURL, Data: validStatus, Status: 200, Response: ""}, - {Label: "Invalid Msg Type", URL: receiveURL, Data: invalidMsgType, Status: 400, Response: ""}, + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111")}, + {Label: "Receive Valid", URL: receiveURL, Data: validReceiveNoMsgType, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111")}, + {Label: "Receive Missing Number", URL: receiveURL, Data: missingNumber, ExpectedStatus: 400, ExpectedResponse: ""}, + {Label: "Status No params", URL: receiveURL, Data: "", ExpectedStatus: 405, ExpectedResponse: ""}, + {Label: "Status invalid params", URL: receiveURL, Data: invalidStatus, ExpectedStatus: 400, ExpectedResponse: ""}, + {Label: "Status valid", URL: receiveURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: ""}, + {Label: "Invalid Msg Type", URL: receiveURL, Data: invalidMsgType, ExpectedStatus: 400, ExpectedResponse: ""}, } func TestHandler(t *testing.T) { diff --git a/handlers/burstsms/burstsms_test.go b/handlers/burstsms/burstsms_test.go index 25fe79f0c..1e2f89d27 100644 --- a/handlers/burstsms/burstsms_test.go +++ b/handlers/burstsms/burstsms_test.go @@ -26,13 +26,13 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL + "?" + validReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Msg"), URN: Sp("tel:+254791541111")}, - {Label: "Receive Missing Number", URL: receiveURL + "?" + missingNumber, Status: 400, Response: "required field 'mobile'"}, + {Label: "Receive Valid", URL: receiveURL + "?" + validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111")}, + {Label: "Receive Missing Number", URL: receiveURL + "?" + missingNumber, ExpectedStatus: 400, ExpectedResponse: "required field 'mobile'"}, - {Label: "Status Valid", URL: statusURL + "?" + validStatus, Status: 200, Response: "Status Update Accepted", - ExternalID: Sp("12345"), MsgStatus: Sp("S")}, - {Label: "Receive Invalid Status", URL: statusURL + "?" + invalidStatus, Status: 400, Response: "unknown status value"}, + {Label: "Status Valid", URL: statusURL + "?" + validStatus, ExpectedStatus: 200, ExpectedResponse: "Status Update Accepted", + ExpectedExternalID: Sp("12345"), ExpectedMsgStatus: Sp("S")}, + {Label: "Receive Invalid Status", URL: statusURL + "?" + invalidStatus, ExpectedStatus: 400, ExpectedResponse: "unknown status value"}, } func TestHandler(t *testing.T) { diff --git a/handlers/chikka/chikka_test.go b/handlers/chikka/chikka_test.go index 58c016fd7..62bf14c1e 100644 --- a/handlers/chikka/chikka_test.go +++ b/handlers/chikka/chikka_test.go @@ -27,17 +27,17 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Hello World"), URN: Sp("tel:+639178020779"), ExternalID: Sp("4004"), - Date: Tp(time.Date(2016, 03, 11, 04, 20, 59, 690000128, time.UTC))}, + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("tel:+639178020779"), ExpectedExternalID: Sp("4004"), + ExpectedDate: Tp(time.Date(2016, 03, 11, 04, 20, 59, 690000128, time.UTC))}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Receive Mising Params", URL: receiveURL, Data: missingParamsReceive, Status: 400, Response: "Field validation for 'RequestID' failed"}, - {Label: "Ignore Invalid message_type", URL: receiveURL, Data: "message_type=invalid", Status: 200, Response: "unknown message_type request"}, - {Label: "Status Sent Valid", URL: receiveURL, Data: validSentStatus, Status: 200, Response: `"status":"S"`}, - {Label: "Status Failed Valid", URL: receiveURL, Data: validFailedStatus, Status: 200, Response: `"status":"F"`}, - {Label: "Status Invalid", URL: receiveURL, Data: invalidStatus, Status: 400, Response: `must be either 'SENT' or 'FAILED'`}, - {Label: "Status Missing Params", URL: receiveURL, Data: missingStatusParams, Status: 400, Response: `Field validation for 'Status' failed `}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Receive Mising Params", URL: receiveURL, Data: missingParamsReceive, ExpectedStatus: 400, ExpectedResponse: "Field validation for 'RequestID' failed"}, + {Label: "Ignore Invalid message_type", URL: receiveURL, Data: "message_type=invalid", ExpectedStatus: 200, ExpectedResponse: "unknown message_type request"}, + {Label: "Status Sent Valid", URL: receiveURL, Data: validSentStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, + {Label: "Status Failed Valid", URL: receiveURL, Data: validFailedStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`}, + {Label: "Status Invalid", URL: receiveURL, Data: invalidStatus, ExpectedStatus: 400, ExpectedResponse: `must be either 'SENT' or 'FAILED'`}, + {Label: "Status Missing Params", URL: receiveURL, Data: missingStatusParams, ExpectedStatus: 400, ExpectedResponse: `Field validation for 'Status' failed `}, } func TestHandler(t *testing.T) { diff --git a/handlers/clickatell/clickatell_test.go b/handlers/clickatell/clickatell_test.go index dd980bd77..a90b83bc2 100644 --- a/handlers/clickatell/clickatell_test.go +++ b/handlers/clickatell/clickatell_test.go @@ -145,23 +145,23 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Valid Receive", URL: receiveURL, Data: receiveValidMessage, Status: 200, Response: "Accepted", - Text: Sp("Hello World!"), URN: Sp("tel:+250788383383"), ExternalID: Sp("1234"), Date: Tp(time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC))}, - {Label: "Valid Receive ISO-8859-1", URL: receiveURL, Data: receiveValidMessageISO8859_1, Status: 200, Response: "Accepted", - Text: Sp(`hello!`), URN: Sp("tel:+250788383383"), ExternalID: Sp("1234"), Date: Tp(time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC))}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Error invalid JSON", URL: receiveURL, Data: "foo", Status: 400, Response: `unable to parse request JSON`}, - {Label: "Error missing JSON", URL: receiveURL, Data: "{}", Status: 400, Response: `missing one of 'messageId`}, - {Label: "Valid Receive UTF-16BE", URL: receiveURL, Data: receiveValidMessageUTF16BE, Status: 200, Response: "Accepted", - Text: Sp("mexico k mis papas no tenýa dinero para comprarnos lo q querýamos.."), URN: Sp("tel:+250788383383"), - ExternalID: Sp("1234"), Date: Tp(time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC))}, - - {Label: "Valid Failed status report", URL: statusURL, Data: statusFailed, Status: 200, Response: `"status":"F"`}, - {Label: "Valid Delivered status report", URL: statusURL, Data: statusSent, Status: 200, Response: `"status":"S"`}, - {Label: "Unexpected status report", URL: statusURL, Data: statusUnexpected, Status: 400, Response: `unknown status '-1', must be one`}, - - {Label: "Invalid status report", URL: statusURL, Data: "{}", Status: 400, Response: `missing one of 'messageId'`}, - {Label: "Invalid JSON", URL: statusURL, Data: "foo", Status: 400, Response: `unable to parse request JSON`}, + {Label: "Valid Receive", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Hello World!"), ExpectedURN: Sp("tel:+250788383383"), ExpectedExternalID: Sp("1234"), ExpectedDate: Tp(time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC))}, + {Label: "Valid Receive ISO-8859-1", URL: receiveURL, Data: receiveValidMessageISO8859_1, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(`hello!`), ExpectedURN: Sp("tel:+250788383383"), ExpectedExternalID: Sp("1234"), ExpectedDate: Tp(time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC))}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Error invalid JSON", URL: receiveURL, Data: "foo", ExpectedStatus: 400, ExpectedResponse: `unable to parse request JSON`}, + {Label: "Error missing JSON", URL: receiveURL, Data: "{}", ExpectedStatus: 400, ExpectedResponse: `missing one of 'messageId`}, + {Label: "Valid Receive UTF-16BE", URL: receiveURL, Data: receiveValidMessageUTF16BE, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("mexico k mis papas no tenýa dinero para comprarnos lo q querýamos.."), ExpectedURN: Sp("tel:+250788383383"), + ExpectedExternalID: Sp("1234"), ExpectedDate: Tp(time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC))}, + + {Label: "Valid Failed status report", URL: statusURL, Data: statusFailed, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`}, + {Label: "Valid Delivered status report", URL: statusURL, Data: statusSent, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, + {Label: "Unexpected status report", URL: statusURL, Data: statusUnexpected, ExpectedStatus: 400, ExpectedResponse: `unknown status '-1', must be one`}, + + {Label: "Invalid status report", URL: statusURL, Data: "{}", ExpectedStatus: 400, ExpectedResponse: `missing one of 'messageId'`}, + {Label: "Invalid JSON", URL: statusURL, Data: "foo", ExpectedStatus: 400, ExpectedResponse: `unable to parse request JSON`}, } func TestHandler(t *testing.T) { diff --git a/handlers/clickmobile/clickmobile_test.go b/handlers/clickmobile/clickmobile_test.go index 4daa98925..21c76f0c4 100644 --- a/handlers/clickmobile/clickmobile_test.go +++ b/handlers/clickmobile/clickmobile_test.go @@ -67,21 +67,21 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: validReceive, Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+265990099333"), ExternalID: Sp("1232434354")}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURNReceive, Status: 400, Response: "phone number supplied is not a number"}, + {Label: "Receive Valid Message", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+265990099333"), ExpectedExternalID: Sp("1232434354")}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURNReceive, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Receive valid with empty text", URL: receiveURL, Data: validReceiveEmptyText, Status: 200, Response: "Accepted", - Text: Sp(""), URN: Sp("tel:+265990099333"), ExternalID: Sp("1232434354")}, - {Label: "Receive valid missing text", URL: receiveURL, Data: validMissingText, Status: 200, Response: "Accepted", - Text: Sp(""), URN: Sp("tel:+265990099333"), ExternalID: Sp("1232434354")}, + {Label: "Receive valid with empty text", URL: receiveURL, Data: validReceiveEmptyText, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+265990099333"), ExpectedExternalID: Sp("1232434354")}, + {Label: "Receive valid missing text", URL: receiveURL, Data: validMissingText, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+265990099333"), ExpectedExternalID: Sp("1232434354")}, - {Label: "Receive valid missing referenceID", URL: receiveURL, Data: validMissingReferenceID, Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+265990099333"), ExternalID: Sp("")}, + {Label: "Receive valid missing referenceID", URL: receiveURL, Data: validMissingReferenceID, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+265990099333"), ExpectedExternalID: Sp("")}, - {Label: "Missing Shortcode", URL: receiveURL, Data: missingShortcode, Status: 400, Response: "missing parameters, must have 'mobile' and 'shortcode'"}, - {Label: "Missing Mobile", URL: receiveURL, Data: missingMobile, Status: 400, Response: "missing parameters, must have 'mobile' and 'shortcode'"}, - {Label: "Receive invalid XML", URL: receiveURL, Data: notXML, Status: 400, Response: "unable to parse request XML"}, + {Label: "Missing Shortcode", URL: receiveURL, Data: missingShortcode, ExpectedStatus: 400, ExpectedResponse: "missing parameters, must have 'mobile' and 'shortcode'"}, + {Label: "Missing Mobile", URL: receiveURL, Data: missingMobile, ExpectedStatus: 400, ExpectedResponse: "missing parameters, must have 'mobile' and 'shortcode'"}, + {Label: "Receive invalid XML", URL: receiveURL, Data: notXML, ExpectedStatus: 400, ExpectedResponse: "unable to parse request XML"}, } func TestHandler(t *testing.T) { diff --git a/handlers/clicksend/clicksend_test.go b/handlers/clicksend/clicksend_test.go index b7033b698..90d5f011d 100644 --- a/handlers/clicksend/clicksend_test.go +++ b/handlers/clicksend/clicksend_test.go @@ -19,9 +19,9 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveURL, Data: `from=639171234567&body=hello+world`, Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - Status: 200, Response: "Accepted", Text: Sp("hello world"), URN: Sp("tel:+639171234567")}, + ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+639171234567")}, {Label: "Receive Missing From", URL: receiveURL, Data: `body=hello+world`, Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - Status: 400, Response: "Error"}, + ExpectedStatus: 400, ExpectedResponse: "Error"}, } func TestHandler(t *testing.T) { diff --git a/handlers/dart/dart_test.go b/handlers/dart/dart_test.go index c15b82e99..33a2d5713 100644 --- a/handlers/dart/dart_test.go +++ b/handlers/dart/dart_test.go @@ -30,16 +30,16 @@ var ( ) var daTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: validMessage, Status: 200, Response: "000", Text: Sp("Msg"), URN: Sp("tel:+6289881134560")}, - {Label: "Receive Valid", URL: externalURN, Status: 200, Response: "000", Text: Sp("Msg"), URN: Sp("ext:cmp-oodddqddwdwdcd")}, - {Label: "Receive Invalid", URL: invalidMessage, Status: 400, Response: "missing required parameters original and sendto"}, + {Label: "Receive Valid", URL: validMessage, ExpectedStatus: 200, ExpectedResponse: "000", ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+6289881134560")}, + {Label: "Receive Valid", URL: externalURN, ExpectedStatus: 200, ExpectedResponse: "000", ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("ext:cmp-oodddqddwdwdcd")}, + {Label: "Receive Invalid", URL: invalidMessage, ExpectedStatus: 400, ExpectedResponse: "missing required parameters original and sendto"}, - {Label: "Valid Status", URL: validStatus, Status: 200, Response: "000", MsgStatus: Sp("D")}, - {Label: "Valid Status", URL: validPartStatus, Status: 200, Response: "000", MsgStatus: Sp("D")}, - {Label: "Failed Status", URL: failedStatus, Status: 200, Response: "000", MsgStatus: Sp("F")}, - {Label: "Missing Status", URL: missingStatus, Status: 400, Response: "parameters messageid and status should not be empty"}, - {Label: "Missing Status", URL: badStatus, Status: 400, Response: "parsing failed: status 'foo' is not an integer"}, - {Label: "Missing Status", URL: badStatusMessageID, Status: 400, Response: "parsing failed: messageid 'abc' is not an integer"}, + {Label: "Valid Status", URL: validStatus, ExpectedStatus: 200, ExpectedResponse: "000", ExpectedMsgStatus: Sp("D")}, + {Label: "Valid Status", URL: validPartStatus, ExpectedStatus: 200, ExpectedResponse: "000", ExpectedMsgStatus: Sp("D")}, + {Label: "Failed Status", URL: failedStatus, ExpectedStatus: 200, ExpectedResponse: "000", ExpectedMsgStatus: Sp("F")}, + {Label: "Missing Status", URL: missingStatus, ExpectedStatus: 400, ExpectedResponse: "parameters messageid and status should not be empty"}, + {Label: "Missing Status", URL: badStatus, ExpectedStatus: 400, ExpectedResponse: "parsing failed: status 'foo' is not an integer"}, + {Label: "Missing Status", URL: badStatusMessageID, ExpectedStatus: 400, ExpectedResponse: "parsing failed: messageid 'abc' is not an integer"}, } func TestHandler(t *testing.T) { diff --git a/handlers/discord/discord_test.go b/handlers/discord/discord_test.go index c742a273c..9770b8a58 100644 --- a/handlers/discord/discord_test.go +++ b/handlers/discord/discord_test.go @@ -23,13 +23,13 @@ var testChannels = []courier.Channel{ } var testCases = []ChannelHandleTestCase{ - {Label: "Recieve Message", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", Data: `from=694634743521607802&text=hello`, Status: 200, Text: Sp("hello"), URN: Sp("discord:694634743521607802")}, - {Label: "Recieve Message with attachment", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", Data: `from=694634743521607802&text=hello&attachments=https://test.test/foo.png`, Status: 200, Text: Sp("hello"), URN: Sp("discord:694634743521607802"), Attachments: []string{"https://test.test/foo.png"}}, - {Label: "Invalid ID", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", Data: `from=somebody&text=hello`, Status: 400, Response: "Error"}, - {Label: "Garbage Body", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", Data: `sdfaskdfajsdkfajsdfaksdf`, Status: 400, Response: "Error"}, - {Label: "Missing Text", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", Data: `from=694634743521607802`, Status: 400, Response: "Error"}, - {Label: "Message Sent Handler", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/sent/", Data: `id=12345`, Status: 200, Response: `"status":"S"`}, - {Label: "Message Sent Handler Garbage", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/sent/", Data: `nothing`, Status: 400}, + {Label: "Recieve Message", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", Data: `from=694634743521607802&text=hello`, ExpectedStatus: 200, ExpectedMsgText: Sp("hello"), ExpectedURN: Sp("discord:694634743521607802")}, + {Label: "Recieve Message with attachment", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", Data: `from=694634743521607802&text=hello&attachments=https://test.test/foo.png`, ExpectedStatus: 200, ExpectedMsgText: Sp("hello"), ExpectedURN: Sp("discord:694634743521607802"), ExpectedAttachments: []string{"https://test.test/foo.png"}}, + {Label: "Invalid ID", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", Data: `from=somebody&text=hello`, ExpectedStatus: 400, ExpectedResponse: "Error"}, + {Label: "Garbage Body", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", Data: `sdfaskdfajsdkfajsdfaksdf`, ExpectedStatus: 400, ExpectedResponse: "Error"}, + {Label: "Missing Text", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", Data: `from=694634743521607802`, ExpectedStatus: 400, ExpectedResponse: "Error"}, + {Label: "Message Sent Handler", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/sent/", Data: `id=12345`, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, + {Label: "Message Sent Handler Garbage", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/sent/", Data: `nothing`, ExpectedStatus: 400}, } var sendTestCases = []ChannelSendTestCase{ diff --git a/handlers/dmark/dmark_test.go b/handlers/dmark/dmark_test.go index bbf921396..fabbe1c19 100644 --- a/handlers/dmark/dmark_test.go +++ b/handlers/dmark/dmark_test.go @@ -30,17 +30,17 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Msg"), URN: Sp("tel:+254791541111"), - Date: Tp(time.Date(2017, 10, 26, 15, 51, 32, 906335000, time.UTC))}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Receive Empty", URL: receiveURL, Data: emptyReceive, Status: 400, Response: "field 'msisdn' required"}, - {Label: "Receive Missing Text", URL: receiveURL, Data: missingText, Status: 400, Response: "field 'text' required"}, - {Label: "Receive Invalid TS", URL: receiveURL, Data: invalidTS, Status: 400, Response: "invalid tstamp"}, + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111"), + ExpectedDate: Tp(time.Date(2017, 10, 26, 15, 51, 32, 906335000, time.UTC))}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Receive Empty", URL: receiveURL, Data: emptyReceive, ExpectedStatus: 400, ExpectedResponse: "field 'msisdn' required"}, + {Label: "Receive Missing Text", URL: receiveURL, Data: missingText, ExpectedStatus: 400, ExpectedResponse: "field 'text' required"}, + {Label: "Receive Invalid TS", URL: receiveURL, Data: invalidTS, ExpectedStatus: 400, ExpectedResponse: "invalid tstamp"}, - {Label: "Status Invalid", URL: statusURL, Status: 400, Data: invalidStatus, Response: "unknown status"}, - {Label: "Status Missing", URL: statusURL, Status: 400, Data: missingStatus, Response: "field 'status' required"}, - {Label: "Status Valid", URL: statusURL, Status: 200, Data: validStatus, Response: `"status":"D"`}, + {Label: "Status Invalid", URL: statusURL, ExpectedStatus: 400, Data: invalidStatus, ExpectedResponse: "unknown status"}, + {Label: "Status Missing", URL: statusURL, ExpectedStatus: 400, Data: missingStatus, ExpectedResponse: "field 'status' required"}, + {Label: "Status Valid", URL: statusURL, ExpectedStatus: 200, Data: validStatus, ExpectedResponse: `"status":"D"`}, } func TestHandler(t *testing.T) { diff --git a/handlers/external/external_test.go b/handlers/external/external_test.go index 681a7f668..03c1e015d 100644 --- a/handlers/external/external_test.go +++ b/handlers/external/external_test.go @@ -43,35 +43,35 @@ var gmChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729")}, - {Label: "Receive Valid Post", URL: receiveNoParams, Data: "sender=%2B2349067554729&text=Join", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729")}, - - {Label: "Receive Valid Post multipart form", URL: receiveNoParams, MultipartFormFields: map[string]string{"sender": "2349067554729", "text": "Join"}, Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729")}, - {Label: "Receive Valid From", URL: receiveValidMessageFrom, Data: "empty", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729")}, - {Label: "Receive Country Parse", URL: receiveValidNoPlus, Data: "empty", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729")}, - {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "empty", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729"), Date: Tp(time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC))}, - {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "empty", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729"), Date: Tp(time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC))}, - {Label: "Invalid URN", URL: invalidURN, Data: "empty", Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", Status: 400, Response: "must have one of 'sender' or 'from' set"}, - {Label: "Receive No Sender", URL: receiveNoSender, Data: "empty", Status: 400, Response: "must have one of 'sender' or 'from' set"}, - {Label: "Receive Invalid Date", URL: receiveInvalidDate, Data: "empty", Status: 400, Response: "invalid date format, must be RFC 3339"}, - {Label: "Failed No Params", URL: failedNoParams, Status: 400, Response: "field 'id' required"}, - {Label: "Failed Valid", URL: failedValid, Status: 200, Response: `"status":"F"`}, - {Label: "Invalid Status", URL: invalidStatus, Status: 404, Response: `page not found`}, - {Label: "Sent Valid", URL: sentValid, Status: 200, Response: `"status":"S"`}, - {Label: "Delivered Valid", URL: deliveredValid, Status: 200, Data: "nothing", Response: `"status":"D"`}, - {Label: "Delivered Valid Post", URL: deliveredValidPost, Data: "id=12345", Status: 200, Response: `"status":"D"`}, - {Label: "Stopped Event", URL: stoppedEvent, Status: 200, Data: "nothing", Response: "Accepted"}, - {Label: "Stopped Event Post", URL: stoppedEventPost, Data: "from=%2B2349067554729", Status: 200, Response: "Accepted"}, - {Label: "Stopped Event Invalid URN", URL: stoppedEventInvalidURN, Data: "empty", Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Stopped event No Params", URL: stoppedEventPost, Status: 400, Response: "field 'from' required"}, + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + {Label: "Receive Valid Post", URL: receiveNoParams, Data: "sender=%2B2349067554729&text=Join", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + + {Label: "Receive Valid Post multipart form", URL: receiveNoParams, MultipartFormFields: map[string]string{"sender": "2349067554729", "text": "Join"}, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + {Label: "Receive Valid From", URL: receiveValidMessageFrom, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + {Label: "Receive Country Parse", URL: receiveValidNoPlus, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: Tp(time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC))}, + {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: Tp(time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC))}, + {Label: "Invalid URN", URL: invalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from' set"}, + {Label: "Receive No Sender", URL: receiveNoSender, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from' set"}, + {Label: "Receive Invalid Date", URL: receiveInvalidDate, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "invalid date format, must be RFC 3339"}, + {Label: "Failed No Params", URL: failedNoParams, ExpectedStatus: 400, ExpectedResponse: "field 'id' required"}, + {Label: "Failed Valid", URL: failedValid, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`}, + {Label: "Invalid Status", URL: invalidStatus, ExpectedStatus: 404, ExpectedResponse: `page not found`}, + {Label: "Sent Valid", URL: sentValid, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, + {Label: "Delivered Valid", URL: deliveredValid, ExpectedStatus: 200, Data: "nothing", ExpectedResponse: `"status":"D"`}, + {Label: "Delivered Valid Post", URL: deliveredValidPost, Data: "id=12345", ExpectedStatus: 200, ExpectedResponse: `"status":"D"`}, + {Label: "Stopped Event", URL: stoppedEvent, ExpectedStatus: 200, Data: "nothing", ExpectedResponse: "Accepted"}, + {Label: "Stopped Event Post", URL: stoppedEventPost, Data: "from=%2B2349067554729", ExpectedStatus: 200, ExpectedResponse: "Accepted"}, + {Label: "Stopped Event Invalid URN", URL: stoppedEventInvalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Stopped event No Params", URL: stoppedEventPost, ExpectedStatus: 400, ExpectedResponse: "field 'from' required"}, } var testSOAPReceiveChannels = []courier.Channel{ @@ -85,15 +85,15 @@ var testSOAPReceiveChannels = []courier.Channel{ var handleSOAPReceiveTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Post SOAP", URL: receiveNoParams, Data: `2349067554729Join`, - Status: 200, Response: "0", - Text: Sp("Join"), URN: Sp("tel:+2349067554729")}, + ExpectedStatus: 200, ExpectedResponse: "0", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, {Label: "Receive Invalid SOAP", URL: receiveNoParams, Data: ``, - Status: 400, Response: "missing from"}, + ExpectedStatus: 400, ExpectedResponse: "missing from"}, } var gmTestCases = []ChannelHandleTestCase{ - {Label: "Receive Non Plus Message", URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sender=2207222333&text=Join", Data: "empty", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2207222333")}, + {Label: "Receive Non Plus Message", URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sender=2207222333&text=Join", Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2207222333")}, } var customChannels = []courier.Channel{ @@ -105,9 +105,9 @@ var customChannels = []courier.Channel{ })} var customTestCases = []ChannelHandleTestCase{ - {Label: "Receive Custom Message", URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?from_number=12067799192&messageText=Join×tamp=2017-06-23T12:30:00Z", Data: "empty", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+12067799192"), Date: Tp(time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC))}, - {Label: "Receive Custom Missing", URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sent_from=12067799192&messageText=Join", Data: "empty", Status: 400, Response: "must have one of 'sender' or 'from' set"}, + {Label: "Receive Custom Message", URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?from_number=12067799192&messageText=Join×tamp=2017-06-23T12:30:00Z", Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+12067799192"), ExpectedDate: Tp(time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC))}, + {Label: "Receive Custom Missing", URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sent_from=12067799192&messageText=Join", Data: "empty", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from' set"}, } func TestHandler(t *testing.T) { diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index 4de993ccf..c4a438a04 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -417,51 +417,51 @@ var unkownMessagingEntry = `{ var notJSON = `blargh` var testCases = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: helloMsg, Status: 200, Response: "Handled", - Text: Sp("Hello World"), URN: Sp("facebook:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, - {Label: "No Duplicate Receive Message", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: duplicateMsg, Status: 200, Response: "Handled", - Text: Sp("Hello World"), URN: Sp("facebook:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, - {Label: "Receive Attachment", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: attachment, Status: 200, Response: "Handled", - Text: Sp(""), Attachments: []string{"https://image-url/foo.png"}, URN: Sp("facebook:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, + {Label: "Receive Message", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, + {Label: "No Duplicate Receive Message", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: duplicateMsg, ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, + {Label: "Receive Attachment", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: attachment, ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, - {Label: "Receive Location", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: locationAttachment, Status: 200, Response: "Handled", - Text: Sp(""), Attachments: []string{"geo:1.200000,-1.300000"}, URN: Sp("facebook:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, + {Label: "Receive Location", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: locationAttachment, ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, - {Label: "Receive Thumbs Up", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: thumbsUp, Status: 200, Response: "Handled", - Text: Sp("👍"), URN: Sp("facebook:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, + {Label: "Receive Thumbs Up", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: thumbsUp, ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedMsgText: Sp("👍"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, - {Label: "Receive OptIn UserRef", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: optInUserRef, Status: 200, Response: "Handled", - URN: Sp("facebook:ref:optin_user_ref"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive OptIn UserRef", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: optInUserRef, ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:ref:optin_user_ref"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}}, - {Label: "Receive OptIn", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: optIn, Status: 200, Response: "Handled", - URN: Sp("facebook:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive OptIn", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: optIn, ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}}, - {Label: "Receive Get Started", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: postbackGetStarted, Status: 200, Response: "Handled", - URN: Sp("facebook:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.NewConversation), + {Label: "Receive Get Started", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: postbackGetStarted, ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.NewConversation), ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}}, - {Label: "Receive Referral Postback", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: postback, Status: 200, Response: "Handled", - URN: Sp("facebook:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), + {Label: "Receive Referral Postback", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: postback, ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}}, - {Label: "Receive Referral", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: postbackReferral, Status: 200, Response: "Handled", - URN: Sp("facebook:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), + {Label: "Receive Referral", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: postbackReferral, ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}}, - {Label: "Receive Referral", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: referral, Status: 200, Response: `"referrer_id":"referral id"`, - URN: Sp("facebook:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), + {Label: "Receive Referral", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: referral, ExpectedStatus: 200, ExpectedResponse: `"referrer_id":"referral id"`, + ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}}, - {Label: "Receive DLR", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: dlr, Status: 200, Response: "Handled", - Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), MsgStatus: Sp(courier.MsgDelivered), ExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233")}, - - {Label: "Different Page", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: differentPage, Status: 200, Response: `"data":[]`}, - {Label: "Echo", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: echo, Status: 200, Response: `ignoring echo`}, - {Label: "Not Page", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: notPage, Status: 200, Response: "ignoring"}, - {Label: "No Entries", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: noEntries, Status: 200, Response: "ignoring"}, - {Label: "No Messaging Entries", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: noMessagingEntries, Status: 200, Response: "Handled"}, - {Label: "Unknown Messaging Entry", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: unkownMessagingEntry, Status: 200, Response: "Handled"}, - {Label: "Not JSON", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: notJSON, Status: 400, Response: "Error"}, - {Label: "Invalid URN", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidURN, Status: 400, Response: "invalid facebook id"}, + {Label: "Receive DLR", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: dlr, ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ExpectedMsgStatus: Sp(courier.MsgDelivered), ExpectedExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233")}, + + {Label: "Different Page", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: differentPage, ExpectedStatus: 200, ExpectedResponse: `"data":[]`}, + {Label: "Echo", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: echo, ExpectedStatus: 200, ExpectedResponse: `ignoring echo`}, + {Label: "Not Page", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: notPage, ExpectedStatus: 200, ExpectedResponse: "ignoring"}, + {Label: "No Entries", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: noEntries, ExpectedStatus: 200, ExpectedResponse: "ignoring"}, + {Label: "No Messaging Entries", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: noMessagingEntries, ExpectedStatus: 200, ExpectedResponse: "Handled"}, + {Label: "Unknown Messaging Entry", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: unkownMessagingEntry, ExpectedStatus: 200, ExpectedResponse: "Handled"}, + {Label: "Not JSON", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "Error"}, + {Label: "Invalid URN", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "invalid facebook id"}, } // mocks the call to the Facebook graph API @@ -541,11 +541,11 @@ func TestVerify(t *testing.T) { subscribeTimeout = time.Millisecond RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ - {Label: "Receive Message", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: helloMsg, Status: 200}, - {Label: "Verify No Mode", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Status: 400, Response: "unknown request"}, - {Label: "Verify No Secret", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe", Status: 400, Response: "token does not match secret"}, - {Label: "Invalid Secret", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe&hub.verify_token=blah", Status: 400, Response: "token does not match secret"}, - {Label: "Valid Secret", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe&hub.verify_token=mysecret&hub.challenge=yarchallenge", Status: 200, Response: "yarchallenge"}, + {Label: "Receive Message", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: helloMsg, ExpectedStatus: 200}, + {Label: "Verify No Mode", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", ExpectedStatus: 400, ExpectedResponse: "unknown request"}, + {Label: "Verify No Secret", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe", ExpectedStatus: 400, ExpectedResponse: "token does not match secret"}, + {Label: "Invalid Secret", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe&hub.verify_token=blah", ExpectedStatus: 400, ExpectedResponse: "token does not match secret"}, + {Label: "Valid Secret", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe&hub.verify_token=mysecret&hub.challenge=yarchallenge", ExpectedStatus: 200, ExpectedResponse: "yarchallenge"}, }) // wait for our subscribe to be called diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 86b4ad7d8..23bcfd798 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -31,98 +31,98 @@ var testChannelsWAC = []courier.Channel{ } var testCasesFBA = []ChannelHandleTestCase{ - {Label: "Receive Message FBA", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - Text: Sp("Hello World"), URN: Sp("facebook:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive Message FBA", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Invalid Signature", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), Status: 400, Response: "invalid request signature", PrepRequest: addInvalidSignature}, + {Label: "Receive Invalid Signature", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), ExpectedStatus: 400, ExpectedResponse: "invalid request signature", PrepRequest: addInvalidSignature}, - {Label: "No Duplicate Receive Message", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/duplicateMsgFBA.json")), Status: 200, Response: "Handled", - Text: Sp("Hello World"), URN: Sp("facebook:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "No Duplicate Receive Message", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/duplicateMsgFBA.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Attachment", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/attachmentFBA.json")), Status: 200, Response: "Handled", - Text: Sp(""), Attachments: []string{"https://image-url/foo.png"}, URN: Sp("facebook:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive Attachment", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/attachmentFBA.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Location", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/locationAttachment.json")), Status: 200, Response: "Handled", - Text: Sp(""), Attachments: []string{"geo:1.200000,-1.300000"}, URN: Sp("facebook:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive Location", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/locationAttachment.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Thumbs Up", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/thumbsUp.json")), Status: 200, Response: "Handled", - Text: Sp("👍"), URN: Sp("facebook:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive Thumbs Up", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/thumbsUp.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedMsgText: Sp("👍"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive OptIn UserRef", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/optInUserRef.json")), Status: 200, Response: "Handled", - URN: Sp("facebook:ref:optin_user_ref"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive OptIn UserRef", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/optInUserRef.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:ref:optin_user_ref"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, PrepRequest: addValidSignature}, - {Label: "Receive OptIn", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/optIn.json")), Status: 200, Response: "Handled", - URN: Sp("facebook:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive OptIn", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/optIn.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, PrepRequest: addValidSignature}, - {Label: "Receive Get Started", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postbackGetStarted.json")), Status: 200, Response: "Handled", - URN: Sp("facebook:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.NewConversation), + {Label: "Receive Get Started", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postbackGetStarted.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.NewConversation), ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, PrepRequest: addValidSignature}, - {Label: "Receive Referral Postback", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postback.json")), Status: 200, Response: "Handled", - URN: Sp("facebook:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), + {Label: "Receive Referral Postback", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postback.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, PrepRequest: addValidSignature}, - {Label: "Receive Referral", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postbackReferral.json")), Status: 200, Response: "Handled", - URN: Sp("facebook:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), + {Label: "Receive Referral", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postbackReferral.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, PrepRequest: addValidSignature}, - {Label: "Receive Referral", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/referral.json")), Status: 200, Response: `"referrer_id":"referral id"`, - URN: Sp("facebook:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), + {Label: "Receive Referral", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/referral.json")), ExpectedStatus: 200, ExpectedResponse: `"referrer_id":"referral id"`, + ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, PrepRequest: addValidSignature}, - {Label: "Receive DLR", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/dlr.json")), Status: 200, Response: "Handled", - Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), MsgStatus: Sp(courier.MsgDelivered), ExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233"), + {Label: "Receive DLR", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/dlr.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ExpectedMsgStatus: Sp(courier.MsgDelivered), ExpectedExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233"), PrepRequest: addValidSignature}, - {Label: "Different Page", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/differentPageFBA.json")), Status: 200, Response: `"data":[]`, PrepRequest: addValidSignature}, - {Label: "Echo", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/echoFBA.json")), Status: 200, Response: `ignoring echo`, PrepRequest: addValidSignature}, - {Label: "Not Page", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/notPage.json")), Status: 400, Response: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notpage", PrepRequest: addValidSignature}, - {Label: "No Entries", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/noEntriesFBA.json")), Status: 400, Response: "no entries found", PrepRequest: addValidSignature}, - {Label: "No Messaging Entries", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/noMessagingEntriesFBA.json")), Status: 200, Response: "Handled", PrepRequest: addValidSignature}, - {Label: "Unknown Messaging Entry", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/unknownMessagingEntryFBA.json")), Status: 200, Response: "Handled", PrepRequest: addValidSignature}, - {Label: "Not JSON", URL: "/c/fba/receive", Data: "not JSON", Status: 400, Response: "Error", PrepRequest: addValidSignature}, - {Label: "Invalid URN", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/invalidURNFBA.json")), Status: 400, Response: "invalid facebook id", PrepRequest: addValidSignature}, + {Label: "Different Page", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/differentPageFBA.json")), ExpectedStatus: 200, ExpectedResponse: `"data":[]`, PrepRequest: addValidSignature}, + {Label: "Echo", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/echoFBA.json")), ExpectedStatus: 200, ExpectedResponse: `ignoring echo`, PrepRequest: addValidSignature}, + {Label: "Not Page", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/notPage.json")), ExpectedStatus: 400, ExpectedResponse: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notpage", PrepRequest: addValidSignature}, + {Label: "No Entries", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/noEntriesFBA.json")), ExpectedStatus: 400, ExpectedResponse: "no entries found", PrepRequest: addValidSignature}, + {Label: "No Messaging Entries", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/noMessagingEntriesFBA.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", PrepRequest: addValidSignature}, + {Label: "Unknown Messaging Entry", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/unknownMessagingEntryFBA.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", PrepRequest: addValidSignature}, + {Label: "Not JSON", URL: "/c/fba/receive", Data: "not JSON", ExpectedStatus: 400, ExpectedResponse: "Error", PrepRequest: addValidSignature}, + {Label: "Invalid URN", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/invalidURNFBA.json")), ExpectedStatus: 400, ExpectedResponse: "invalid facebook id", PrepRequest: addValidSignature}, } var testCasesIG = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - Text: Sp("Hello World"), URN: Sp("instagram:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive Message", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("instagram:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Invalid Signature", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), Status: 400, Response: "invalid request signature", PrepRequest: addInvalidSignature}, + {Label: "Receive Invalid Signature", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), ExpectedStatus: 400, ExpectedResponse: "invalid request signature", PrepRequest: addInvalidSignature}, - {Label: "No Duplicate Receive Message", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/duplicateMsgIG.json")), Status: 200, Response: "Handled", - Text: Sp("Hello World"), URN: Sp("instagram:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "No Duplicate Receive Message", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/duplicateMsgIG.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("instagram:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Attachment", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/attachmentIG.json")), Status: 200, Response: "Handled", - Text: Sp(""), Attachments: []string{"https://image-url/foo.png"}, URN: Sp("instagram:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive Attachment", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/attachmentIG.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, ExpectedURN: Sp("instagram:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Like Heart", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/like_heart.json")), Status: 200, Response: "Handled", - Text: Sp(""), URN: Sp("instagram:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive Like Heart", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/like_heart.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedMsgText: Sp(""), ExpectedURN: Sp("instagram:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Icebreaker Get Started", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/icebreakerGetStarted.json")), Status: 200, Response: "Handled", - URN: Sp("instagram:5678"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.NewConversation), + {Label: "Receive Icebreaker Get Started", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/icebreakerGetStarted.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", + ExpectedURN: Sp("instagram:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.NewConversation), ChannelEventExtra: map[string]interface{}{"title": "icebreaker question", "payload": "get_started"}, PrepRequest: addValidSignature}, - {Label: "Different Page", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/differentPageIG.json")), Status: 200, Response: `"data":[]`, PrepRequest: addValidSignature}, - {Label: "Echo", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/echoIG.json")), Status: 200, Response: `ignoring echo`, PrepRequest: addValidSignature}, - {Label: "No Entries", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/noEntriesIG.json")), Status: 400, Response: "no entries found", PrepRequest: addValidSignature}, - {Label: "Not Instagram", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/notInstagram.json")), Status: 400, Response: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notinstagram", PrepRequest: addValidSignature}, - {Label: "No Messaging Entries", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/noMessagingEntriesIG.json")), Status: 200, Response: "Handled", PrepRequest: addValidSignature}, - {Label: "Unknown Messaging Entry", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/unknownMessagingEntryIG.json")), Status: 200, Response: "Handled", PrepRequest: addValidSignature}, - {Label: "Not JSON", URL: "/c/ig/receive", Data: "not JSON", Status: 400, Response: "Error", PrepRequest: addValidSignature}, - {Label: "Invalid URN", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/invalidURNIG.json")), Status: 400, Response: "invalid instagram id", PrepRequest: addValidSignature}, - {Label: "Story Mention", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/storyMentionIG.json")), Status: 200, Response: `ignoring story_mention`, PrepRequest: addValidSignature}, - {Label: "Message unsent", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/unsentMsgIG.json")), Status: 200, Response: `msg deleted`, PrepRequest: addValidSignature}, + {Label: "Different Page", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/differentPageIG.json")), ExpectedStatus: 200, ExpectedResponse: `"data":[]`, PrepRequest: addValidSignature}, + {Label: "Echo", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/echoIG.json")), ExpectedStatus: 200, ExpectedResponse: `ignoring echo`, PrepRequest: addValidSignature}, + {Label: "No Entries", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/noEntriesIG.json")), ExpectedStatus: 400, ExpectedResponse: "no entries found", PrepRequest: addValidSignature}, + {Label: "Not Instagram", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/notInstagram.json")), ExpectedStatus: 400, ExpectedResponse: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notinstagram", PrepRequest: addValidSignature}, + {Label: "No Messaging Entries", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/noMessagingEntriesIG.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", PrepRequest: addValidSignature}, + {Label: "Unknown Messaging Entry", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/unknownMessagingEntryIG.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", PrepRequest: addValidSignature}, + {Label: "Not JSON", URL: "/c/ig/receive", Data: "not JSON", ExpectedStatus: 400, ExpectedResponse: "Error", PrepRequest: addValidSignature}, + {Label: "Invalid URN", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/invalidURNIG.json")), ExpectedStatus: 400, ExpectedResponse: "invalid instagram id", PrepRequest: addValidSignature}, + {Label: "Story Mention", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/storyMentionIG.json")), ExpectedStatus: 200, ExpectedResponse: `ignoring story_mention`, PrepRequest: addValidSignature}, + {Label: "Message unsent", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/unsentMsgIG.json")), ExpectedStatus: 200, ExpectedResponse: `msg deleted`, PrepRequest: addValidSignature}, } func addValidSignature(r *http.Request) { @@ -237,50 +237,50 @@ func TestDescribeWAC(t *testing.T) { var wacReceiveURL = "/c/wac/receive" var testCasesWAC = []ChannelHandleTestCase{ - {Label: "Receive Message WAC", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/helloWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - Text: Sp("Hello World"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + {Label: "Receive Message WAC", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/helloWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Duplicate Valid Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/duplicateWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - Text: Sp("Hello World"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + {Label: "Receive Duplicate Valid Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/duplicateWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Voice Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/voiceWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - Text: Sp(""), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Attachment: Sp("https://foo.bar/attachmentURL_Voice"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + {Label: "Receive Valid Voice Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/voiceWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + ExpectedMsgText: Sp(""), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Voice"}, ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Button Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/buttonWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - Text: Sp("No"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + {Label: "Receive Valid Button Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/buttonWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("No"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Document Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/documentWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - Text: Sp("80skaraokesonglistartist"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Attachment: Sp("https://foo.bar/attachmentURL_Document"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + {Label: "Receive Valid Document Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/documentWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("80skaraokesonglistartist"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Document"}, ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Image Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/imageWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - Text: Sp("Check out my new phone!"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Attachment: Sp("https://foo.bar/attachmentURL_Image"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + {Label: "Receive Valid Image Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/imageWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Check out my new phone!"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Image"}, ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Video Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/videoWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - Text: Sp("Check out my new phone!"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Attachment: Sp("https://foo.bar/attachmentURL_Video"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + {Label: "Receive Valid Video Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/videoWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Check out my new phone!"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Video"}, ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Audio Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/audioWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - Text: Sp("Check out my new phone!"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Attachment: Sp("https://foo.bar/attachmentURL_Audio"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + {Label: "Receive Valid Audio Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/audioWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Check out my new phone!"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Audio"}, ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Location Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/locationWAC.json")), Status: 200, Response: `"type":"msg"`, - Text: Sp(""), Attachment: Sp("geo:0.000000,1.000000"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + {Label: "Receive Valid Location Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/locationWAC.json")), ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: "not json", Status: 400, Response: "unable to parse", PrepRequest: addValidSignature}, - {Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidFrom.json")), Status: 400, Response: "invalid whatsapp id", PrepRequest: addValidSignature}, - {Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidTimestamp.json")), Status: 400, Response: "invalid timestamp", PrepRequest: addValidSignature}, + {Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: "not json", ExpectedStatus: 400, ExpectedResponse: "unable to parse", PrepRequest: addValidSignature}, + {Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidFrom.json")), ExpectedStatus: 400, ExpectedResponse: "invalid whatsapp id", PrepRequest: addValidSignature}, + {Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidTimestamp.json")), ExpectedStatus: 400, ExpectedResponse: "invalid timestamp", PrepRequest: addValidSignature}, - {Label: "Receive Valid Status", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/validStatusWAC.json")), Status: 200, Response: `"type":"status"`, - MsgStatus: Sp("S"), ExternalID: Sp("external_id"), PrepRequest: addValidSignature}, - {Label: "Receive Invalid Status", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidStatusWAC.json")), Status: 400, Response: `"unknown status: in_orbit"`, PrepRequest: addValidSignature}, - {Label: "Receive Ignore Status", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/ignoreStatusWAC.json")), Status: 200, Response: `"ignoring status: deleted"`, PrepRequest: addValidSignature}, - {Label: "Receive Valid Interactive Button Reply Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/buttonReplyWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - Text: Sp("Yes"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + {Label: "Receive Valid Status", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/validStatusWAC.json")), ExpectedStatus: 200, ExpectedResponse: `"type":"status"`, + ExpectedMsgStatus: Sp("S"), ExpectedExternalID: Sp("external_id"), PrepRequest: addValidSignature}, + {Label: "Receive Invalid Status", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidStatusWAC.json")), ExpectedStatus: 400, ExpectedResponse: `"unknown status: in_orbit"`, PrepRequest: addValidSignature}, + {Label: "Receive Ignore Status", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/ignoreStatusWAC.json")), ExpectedStatus: 200, ExpectedResponse: `"ignoring status: deleted"`, PrepRequest: addValidSignature}, + {Label: "Receive Valid Interactive Button Reply Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/buttonReplyWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Yes"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Interactive List Reply Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/listReplyWAC.json")), Status: 200, Response: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - Text: Sp("Yes"), URN: Sp("whatsapp:5678"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + {Label: "Receive Valid Interactive List Reply Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/listReplyWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Yes"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), PrepRequest: addValidSignature}, } @@ -347,21 +347,21 @@ func BenchmarkHandler(b *testing.B) { func TestVerify(t *testing.T) { RunChannelTestCases(t, testChannelsFBA, newHandler("FBA", "Facebook", false), []ChannelHandleTestCase{ - {Label: "Valid Secret", URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", Status: 200, - Response: "yarchallenge", NoQueueErrorCheck: true, NoInvalidChannelCheck: true}, - {Label: "Verify No Mode", URL: "/c/fba/receive", Status: 400, Response: "unknown request"}, - {Label: "Verify No Secret", URL: "/c/fba/receive?hub.mode=subscribe", Status: 400, Response: "token does not match secret"}, - {Label: "Invalid Secret", URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=blah", Status: 400, Response: "token does not match secret"}, - {Label: "Valid Secret", URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", Status: 200, Response: "yarchallenge"}, + {Label: "Valid Secret", URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", ExpectedStatus: 200, + ExpectedResponse: "yarchallenge", NoQueueErrorCheck: true, NoInvalidChannelCheck: true}, + {Label: "Verify No Mode", URL: "/c/fba/receive", ExpectedStatus: 400, ExpectedResponse: "unknown request"}, + {Label: "Verify No Secret", URL: "/c/fba/receive?hub.mode=subscribe", ExpectedStatus: 400, ExpectedResponse: "token does not match secret"}, + {Label: "Invalid Secret", URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=blah", ExpectedStatus: 400, ExpectedResponse: "token does not match secret"}, + {Label: "Valid Secret", URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", ExpectedStatus: 200, ExpectedResponse: "yarchallenge"}, }) RunChannelTestCases(t, testChannelsIG, newHandler("IG", "Instagram", false), []ChannelHandleTestCase{ - {Label: "Valid Secret", URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", Status: 200, - Response: "yarchallenge", NoQueueErrorCheck: true, NoInvalidChannelCheck: true}, - {Label: "Verify No Mode", URL: "/c/ig/receive", Status: 400, Response: "unknown request"}, - {Label: "Verify No Secret", URL: "/c/ig/receive?hub.mode=subscribe", Status: 400, Response: "token does not match secret"}, - {Label: "Invalid Secret", URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=blah", Status: 400, Response: "token does not match secret"}, - {Label: "Valid Secret", URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", Status: 200, Response: "yarchallenge"}, + {Label: "Valid Secret", URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", ExpectedStatus: 200, + ExpectedResponse: "yarchallenge", NoQueueErrorCheck: true, NoInvalidChannelCheck: true}, + {Label: "Verify No Mode", URL: "/c/ig/receive", ExpectedStatus: 400, ExpectedResponse: "unknown request"}, + {Label: "Verify No Secret", URL: "/c/ig/receive?hub.mode=subscribe", ExpectedStatus: 400, ExpectedResponse: "token does not match secret"}, + {Label: "Invalid Secret", URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=blah", ExpectedStatus: 400, ExpectedResponse: "token does not match secret"}, + {Label: "Valid Secret", URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", ExpectedStatus: 200, ExpectedResponse: "yarchallenge"}, }) } diff --git a/handlers/firebase/firebase_test.go b/handlers/firebase/firebase_test.go index 9494db480..9295eeb29 100644 --- a/handlers/firebase/firebase_test.go +++ b/handlers/firebase/firebase_test.go @@ -50,13 +50,13 @@ var testChannels = []courier.Channel{ } var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: validMsg, Status: 200, Response: "Accepted", - Text: Sp("hello world"), URN: Sp("fcm:12345"), Date: Tp(time.Date(2017, 1, 1, 8, 50, 0, 0, time.UTC)), URNAuth: Sp("token"), Name: Sp("fred")}, - {Label: "Receive Invalid Date", URL: receiveURL, Data: invalidDate, Status: 400, Response: "unable to parse date"}, - {Label: "Receive Missing From", URL: receiveURL, Data: missingFrom, Status: 400, Response: "field 'from' required"}, + {Label: "Receive Valid Message", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("fcm:12345"), ExpectedDate: Tp(time.Date(2017, 1, 1, 8, 50, 0, 0, time.UTC)), ExpectedURNAuth: Sp("token"), ExpectedContactName: Sp("fred")}, + {Label: "Receive Invalid Date", URL: receiveURL, Data: invalidDate, ExpectedStatus: 400, ExpectedResponse: "unable to parse date"}, + {Label: "Receive Missing From", URL: receiveURL, Data: missingFrom, ExpectedStatus: 400, ExpectedResponse: "field 'from' required"}, - {Label: "Receive Valid Register", URL: registerURL, Data: validRegister, Status: 200, Response: "contact_uuid"}, - {Label: "Receive Missing URN", URL: registerURL, Data: missingURN, Status: 400, Response: "field 'urn' required"}, + {Label: "Receive Valid Register", URL: registerURL, Data: validRegister, ExpectedStatus: 200, ExpectedResponse: "contact_uuid"}, + {Label: "Receive Missing URN", URL: registerURL, Data: missingURN, ExpectedStatus: 400, ExpectedResponse: "field 'urn' required"}, } func TestHandler(t *testing.T) { diff --git a/handlers/freshchat/freshchat_test.go b/handlers/freshchat/freshchat_test.go index 87c07e718..0beb550ee 100644 --- a/handlers/freshchat/freshchat_test.go +++ b/handlers/freshchat/freshchat_test.go @@ -34,30 +34,30 @@ var sigtestCases = []ChannelHandleTestCase{ Headers: map[string]string{ "Content-Type": "application/json", "X-FreshChat-Signature": validSignature}, - URL: receiveURL, Data: validReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Test 2"), URN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), Date: Tp(time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC))}, + URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Test 2"), ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), ExpectedDate: Tp(time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC))}, {Label: "Bad Signature", Headers: map[string]string{ "Content-Type": "application/json", "X-FreshChat-Signature": invalidSignature}, - URL: receiveURL, Data: validReceive, Status: 400, Response: `{"message":"Error","data":[{"type":"error","error":"unable to verify signature, crypto/rsa: verification error"}]}`, - Text: Sp("Test 2"), URN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), Date: Tp(time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC))}, + URL: receiveURL, Data: validReceive, ExpectedStatus: 400, ExpectedResponse: `{"message":"Error","data":[{"type":"error","error":"unable to verify signature, crypto/rsa: verification error"}]}`, + ExpectedMsgText: Sp("Test 2"), ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), ExpectedDate: Tp(time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC))}, } var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid w Sig", Headers: map[string]string{ "Content-Type": "application/json", "X-FreshChat-Signature": validSignature}, - URL: receiveURL, Data: validReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Test 2"), URN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), Date: Tp(time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC))}, + URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Test 2"), ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), ExpectedDate: Tp(time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC))}, {Label: "Bad JSON", Headers: map[string]string{ "Content-Type": "application/json", "X-FreshChat-Signature": invalidSignature}, - URL: receiveURL, Data: notJSON, Status: 400, Response: `{"message":"Error","data":[{"type":"error","error":"unable to parse request JSON: invalid character 'e' looking for beginning of value"}]}`, - Text: Sp("Test 2"), URN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), Date: Tp(time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC))}, + URL: receiveURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: `{"message":"Error","data":[{"type":"error","error":"unable to parse request JSON: invalid character 'e' looking for beginning of value"}]}`, + ExpectedMsgText: Sp("Test 2"), ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), ExpectedDate: Tp(time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC))}, } func TestHandler(t *testing.T) { diff --git a/handlers/globe/globe_test.go b/handlers/globe/globe_test.go index 8548108d9..7592fcb58 100644 --- a/handlers/globe/globe_test.go +++ b/handlers/globe/globe_test.go @@ -112,13 +112,13 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: validMessage, Status: 200, Response: "Accepted", - Text: Sp("hello world"), URN: Sp("tel:+639171234567"), Date: Tp(time.Date(2013, 11, 22, 12, 12, 13, 0, time.UTC))}, - {Label: "No Messages", URL: receiveURL, Data: noMessages, Status: 200, Response: "Ignored"}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Invalid Sender", URL: receiveURL, Data: invalidSender, Status: 400, Response: "invalid 'senderAddress' parameter"}, - {Label: "Invalid Date", URL: receiveURL, Data: invalidDate, Status: 400, Response: "parsing time"}, - {Label: "Invalid JSON", URL: receiveURL, Data: invalidJSON, Status: 400, Response: "unable to parse request JSON"}, + {Label: "Receive Valid Message", URL: receiveURL, Data: validMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+639171234567"), ExpectedDate: Tp(time.Date(2013, 11, 22, 12, 12, 13, 0, time.UTC))}, + {Label: "No Messages", URL: receiveURL, Data: noMessages, ExpectedStatus: 200, ExpectedResponse: "Ignored"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Invalid Sender", URL: receiveURL, Data: invalidSender, ExpectedStatus: 400, ExpectedResponse: "invalid 'senderAddress' parameter"}, + {Label: "Invalid Date", URL: receiveURL, Data: invalidDate, ExpectedStatus: 400, ExpectedResponse: "parsing time"}, + {Label: "Invalid JSON", URL: receiveURL, Data: invalidJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, } func TestHandler(t *testing.T) { diff --git a/handlers/highconnection/highconnection_test.go b/handlers/highconnection/highconnection_test.go index 4bd0bce3f..65eccf430 100644 --- a/handlers/highconnection/highconnection_test.go +++ b/handlers/highconnection/highconnection_test.go @@ -26,18 +26,18 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: validReceive, Status: 200, Response: "Accepted", - Text: Sp("Hello World"), URN: Sp("tel:+33610346460"), - Date: Tp(time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC))}, - {Label: "Receive Valid Message with accents", URL: receiveURL, Data: validAccentReceive, Status: 200, Response: "Accepted", - Text: Sp("je suis très satisfait "), URN: Sp("tel:+33610346460"), - Date: Tp(time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC))}, + {Label: "Receive Valid Message", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("tel:+33610346460"), + ExpectedDate: Tp(time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC))}, + {Label: "Receive Valid Message with accents", URL: receiveURL, Data: validAccentReceive, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("je suis très satisfait "), ExpectedURN: Sp("tel:+33610346460"), + ExpectedDate: Tp(time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC))}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Receive Missing Params", URL: receiveURL, Data: " ", Status: 400, Response: "validation for 'From' failed"}, - {Label: "Receive Invalid Date", URL: receiveURL, Data: invalidDateReceive, Status: 400, Response: "cannot parse"}, - {Label: "Status Missing Params", URL: statusURL, Status: 400, Response: "validation for 'Status' failed"}, - {Label: "Status Delivered", URL: validStatus, Status: 200, Response: `"status":"D"`}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Receive Missing Params", URL: receiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: "validation for 'From' failed"}, + {Label: "Receive Invalid Date", URL: receiveURL, Data: invalidDateReceive, ExpectedStatus: 400, ExpectedResponse: "cannot parse"}, + {Label: "Status Missing Params", URL: statusURL, ExpectedStatus: 400, ExpectedResponse: "validation for 'Status' failed"}, + {Label: "Status Delivered", URL: validStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`}, } func TestHandler(t *testing.T) { diff --git a/handlers/hormuud/hormuud_test.go b/handlers/hormuud/hormuud_test.go index e4d302a61..c89bd930d 100644 --- a/handlers/hormuud/hormuud_test.go +++ b/handlers/hormuud/hormuud_test.go @@ -26,12 +26,12 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729"), Date: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, - {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", Status: 200, Response: "Accepted", - Text: Sp(""), URN: Sp("tel:+2349067554729"), Date: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", Status: 400, Response: "field 'sender' required"}, - {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", Status: 400, Response: "phone number supplied is not a number"}, + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, + {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, + {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'sender' required"}, + {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, // {Label: "Status No Params", URL: statusNoParams, Status: 400, Response: "field 'status' required"}, // {Label: "Status Invalid Status", URL: statusInvalidStatus, Status: 400, Response: "unknown status '66', must be one of 1,2,4,8,16"}, // {Label: "Status Valid", URL: statusValid, Status: 200, Response: `"status":"S"`}, diff --git a/handlers/i2sms/i2sms_test.go b/handlers/i2sms/i2sms_test.go index ed4c7f208..b733dd593 100644 --- a/handlers/i2sms/i2sms_test.go +++ b/handlers/i2sms/i2sms_test.go @@ -21,9 +21,9 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, Status: 200, Response: "", - Text: Sp("Msg"), URN: Sp("tel:+254791541111")}, - {Label: "Receive Missing Number", URL: receiveURL, Data: missingNumber, Status: 400, Response: "required field 'mobile'"}, + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111")}, + {Label: "Receive Missing Number", URL: receiveURL, Data: missingNumber, ExpectedStatus: 400, ExpectedResponse: "required field 'mobile'"}, } func TestHandler(t *testing.T) { diff --git a/handlers/infobip/infobip_test.go b/handlers/infobip/infobip_test.go index fa61f9495..5274c7dc0 100644 --- a/handlers/infobip/infobip_test.go +++ b/handlers/infobip/infobip_test.go @@ -191,19 +191,19 @@ var invalidStatus = `{ }` var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: helloMsg, Status: 200, Response: "Accepted", - Text: Sp("QUIZ Correct answer is Paris"), URN: Sp("tel:+385916242493"), ExternalID: Sp("817790313235066447"), Date: Tp(time.Date(2016, 10, 06, 9, 28, 39, 220000000, time.FixedZone("", 0)))}, - {Label: "Receive missing results key", URL: receiveURL, Data: missingResults, Status: 400, Response: "validation for 'Results' failed"}, - {Label: "Receive missing text key", URL: receiveURL, Data: missingText, Status: 200, Response: "ignoring request, no message"}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Status report invalid JSON", URL: statusURL, Data: invalidJSONStatus, Status: 400, Response: "unable to parse request JSON"}, - {Label: "Status report missing results key", URL: statusURL, Data: statusMissingResultsKey, Status: 400, Response: "Field validation for 'Results' failed"}, - {Label: "Status delivered", URL: statusURL, Data: validStatusDelivered, Status: 200, Response: `"status":"D"`}, - {Label: "Status rejected", URL: statusURL, Data: validStatusRejected, Status: 200, Response: `"status":"F"`}, - {Label: "Status undeliverable", URL: statusURL, Data: validStatusUndeliverable, Status: 200, Response: `"status":"F"`}, - {Label: "Status pending", URL: statusURL, Data: validStatusPending, Status: 200, Response: `"status":"S"`}, - {Label: "Status expired", URL: statusURL, Data: validStatusExpired, Status: 200, Response: `"status":"S"`}, - {Label: "Status group name unexpected", URL: statusURL, Data: invalidStatus, Status: 400, Response: `unknown status 'UNEXPECTED'`}, + {Label: "Receive Valid Message", URL: receiveURL, Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("QUIZ Correct answer is Paris"), ExpectedURN: Sp("tel:+385916242493"), ExpectedExternalID: Sp("817790313235066447"), ExpectedDate: Tp(time.Date(2016, 10, 06, 9, 28, 39, 220000000, time.FixedZone("", 0)))}, + {Label: "Receive missing results key", URL: receiveURL, Data: missingResults, ExpectedStatus: 400, ExpectedResponse: "validation for 'Results' failed"}, + {Label: "Receive missing text key", URL: receiveURL, Data: missingText, ExpectedStatus: 200, ExpectedResponse: "ignoring request, no message"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Status report invalid JSON", URL: statusURL, Data: invalidJSONStatus, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, + {Label: "Status report missing results key", URL: statusURL, Data: statusMissingResultsKey, ExpectedStatus: 400, ExpectedResponse: "Field validation for 'Results' failed"}, + {Label: "Status delivered", URL: statusURL, Data: validStatusDelivered, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`}, + {Label: "Status rejected", URL: statusURL, Data: validStatusRejected, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`}, + {Label: "Status undeliverable", URL: statusURL, Data: validStatusUndeliverable, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`}, + {Label: "Status pending", URL: statusURL, Data: validStatusPending, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, + {Label: "Status expired", URL: statusURL, Data: validStatusExpired, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, + {Label: "Status group name unexpected", URL: statusURL, Data: invalidStatus, ExpectedStatus: 400, ExpectedResponse: `unknown status 'UNEXPECTED'`}, } func TestHandler(t *testing.T) { diff --git a/handlers/jasmin/jasmin_test.go b/handlers/jasmin/jasmin_test.go index 523dd8092..c561934e2 100644 --- a/handlers/jasmin/jasmin_test.go +++ b/handlers/jasmin/jasmin_test.go @@ -27,20 +27,20 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, Status: 200, Response: "ACK/Jasmin", - Text: Sp("événement"), URN: Sp("tel:+2349067554729"), ExternalID: Sp("1001")}, - {Label: "Receive Missing To", URL: receiveURL, Data: receiveMissingTo, Status: 400, - Response: "field 'to' required"}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, Status: 400, - Response: "phone number supplied is not a number"}, - {Label: "Status Delivered", URL: statusURL, Data: statusDelivered, Status: 200, Response: "ACK/Jasmin", - MsgStatus: Sp("D"), ExternalID: Sp("external1")}, - {Label: "Status Failed", URL: statusURL, Data: statusFailed, Status: 200, Response: "ACK/Jasmin", - MsgStatus: Sp("F"), ExternalID: Sp("external1")}, - {Label: "Status Missing", URL: statusURL, Status: 400, Data: "nothing", - Response: "field 'id' required"}, - {Label: "Status Unknown", URL: statusURL, Status: 400, Data: statusUnknown, - Response: "must have either dlvrd or err set to 1"}, + {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "ACK/Jasmin", + ExpectedMsgText: Sp("événement"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedExternalID: Sp("1001")}, + {Label: "Receive Missing To", URL: receiveURL, Data: receiveMissingTo, ExpectedStatus: 400, + ExpectedResponse: "field 'to' required"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, + ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Status Delivered", URL: statusURL, Data: statusDelivered, ExpectedStatus: 200, ExpectedResponse: "ACK/Jasmin", + ExpectedMsgStatus: Sp("D"), ExpectedExternalID: Sp("external1")}, + {Label: "Status Failed", URL: statusURL, Data: statusFailed, ExpectedStatus: 200, ExpectedResponse: "ACK/Jasmin", + ExpectedMsgStatus: Sp("F"), ExpectedExternalID: Sp("external1")}, + {Label: "Status Missing", URL: statusURL, ExpectedStatus: 400, Data: "nothing", + ExpectedResponse: "field 'id' required"}, + {Label: "Status Unknown", URL: statusURL, ExpectedStatus: 400, Data: statusUnknown, + ExpectedResponse: "must have either dlvrd or err set to 1"}, } func TestHandler(t *testing.T) { diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index 1b0f5bc0d..b093ecc20 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -146,28 +146,28 @@ func addInvalidSignature(r *http.Request) { } var testCases = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: receiveURL, Data: validMsg, Status: 200, Response: "Accepted", - Text: Sp("Simple Message"), URN: Sp("jiochat:1234"), ExternalID: Sp("123456"), - Date: Tp(time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC))}, + {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Simple Message"), ExpectedURN: Sp("jiochat:1234"), ExpectedExternalID: Sp("123456"), + ExpectedDate: Tp(time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC))}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, Status: 400, Response: "invalid jiochat id"}, - {Label: "Missing params", URL: receiveURL, Data: missingParamsRequired, Status: 400, Response: "Error:Field validation"}, - {Label: "Missing params Event or MsgId", URL: receiveURL, Data: missingParams, Status: 400, Response: "missing parameters, must have either 'MsgId' or 'Event'"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "invalid jiochat id"}, + {Label: "Missing params", URL: receiveURL, Data: missingParamsRequired, ExpectedStatus: 400, ExpectedResponse: "Error:Field validation"}, + {Label: "Missing params Event or MsgId", URL: receiveURL, Data: missingParams, ExpectedStatus: 400, ExpectedResponse: "missing parameters, must have either 'MsgId' or 'Event'"}, - {Label: "Receive Image", URL: receiveURL, Data: imageMessage, Status: 200, Response: "Accepted", - Text: Sp(""), URN: Sp("jiochat:1234"), ExternalID: Sp("123456"), - Attachment: Sp("https://channels.jiochat.com/media/download.action?media_id=12"), - Date: Tp(time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC))}, + {Label: "Receive Image", URL: receiveURL, Data: imageMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(""), ExpectedURN: Sp("jiochat:1234"), ExpectedExternalID: Sp("123456"), + ExpectedAttachments: []string{"https://channels.jiochat.com/media/download.action?media_id=12"}, + ExpectedDate: Tp(time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC))}, - {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, Status: 200, Response: "Event Accepted", - ChannelEvent: Sp(courier.NewConversation), URN: Sp("jiochat:1234")}, + {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedStatus: 200, ExpectedResponse: "Event Accepted", + ChannelEvent: Sp(courier.NewConversation), ExpectedURN: Sp("jiochat:1234")}, - {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, Status: 200, Response: "unknown event"}, + {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, ExpectedStatus: 200, ExpectedResponse: "unknown event"}, - {Label: "Verify URL", URL: verifyURL, Status: 200, Response: "SUCCESS", + {Label: "Verify URL", URL: verifyURL, ExpectedStatus: 200, ExpectedResponse: "SUCCESS", PrepRequest: addValidSignature}, - {Label: "Verify URL Invalid signature", URL: verifyURL, Status: 400, Response: "unknown request", + {Label: "Verify URL Invalid signature", URL: verifyURL, ExpectedStatus: 400, ExpectedResponse: "unknown request", PrepRequest: addInvalidSignature}, } @@ -195,12 +195,12 @@ func TestFetchAccessToken(t *testing.T) { fetchTimeout = time.Millisecond RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ - {Label: "Receive Message", URL: receiveURL, Data: validMsg, Status: 200, Response: "Accepted"}, + {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted"}, - {Label: "Verify URL", URL: verifyURL, Status: 200, Response: "SUCCESS", + {Label: "Verify URL", URL: verifyURL, ExpectedStatus: 200, ExpectedResponse: "SUCCESS", PrepRequest: addValidSignature}, - {Label: "Verify URL Invalid signature", URL: verifyURL, Status: 400, Response: "unknown request", + {Label: "Verify URL Invalid signature", URL: verifyURL, ExpectedStatus: 400, ExpectedResponse: "unknown request", PrepRequest: addInvalidSignature}, }) diff --git a/handlers/junebug/junebug_test.go b/handlers/junebug/junebug_test.go index 438e4eeaa..a2bd5fe32 100644 --- a/handlers/junebug/junebug_test.go +++ b/handlers/junebug/junebug_test.go @@ -93,44 +93,44 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: inboundURL, Data: validMsg, Status: 200, Response: "Accepted", - Text: Sp("hello world"), URN: Sp("tel:+250788383383"), - Date: Tp(time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC))}, + {Label: "Receive Valid Message", URL: inboundURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+250788383383"), + ExpectedDate: Tp(time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC))}, {Label: "Invalid URN", URL: inboundURL, Data: invalidURN, - Status: 400, Response: "phone number supplied is not a number"}, + ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Invalid Timestamp", URL: inboundURL, Data: invalidTimestamp, - Status: 400, Response: "unable to parse date"}, + ExpectedStatus: 400, ExpectedResponse: "unable to parse date"}, {Label: "Missing Message ID", URL: inboundURL, Data: missingMessageID, - Status: 400, Response: "'MessageID' failed on the 'required'"}, - - {Label: "Receive Pending Event", URL: eventURL, Data: pendingEvent, Status: 200, Response: "Ignored"}, - {Label: "Receive Sent Event", URL: eventURL, Data: sentEvent, Status: 200, Response: "Accepted", - ExternalID: Sp("xx12345"), MsgStatus: Sp("S")}, - {Label: "Receive Delivered Event", URL: eventURL, Data: deliveredEvent, Status: 200, Response: "Accepted", - ExternalID: Sp("xx12345"), MsgStatus: Sp("D")}, - {Label: "Receive Failed Event", URL: eventURL, Data: failedEvent, Status: 200, Response: "Accepted", - ExternalID: Sp("xx12345"), MsgStatus: Sp("F")}, - {Label: "Receive Unknown Event", URL: eventURL, Data: unknownEvent, Status: 200, Response: "Ignored"}, - - {Label: "Receive Invalid JSON", URL: eventURL, Data: "not json", Status: 400, Response: "Error"}, - {Label: "Receive Missing Event Type", URL: eventURL, Data: missingEventType, Status: 400, Response: "Error"}, + ExpectedStatus: 400, ExpectedResponse: "'MessageID' failed on the 'required'"}, + + {Label: "Receive Pending Event", URL: eventURL, Data: pendingEvent, ExpectedStatus: 200, ExpectedResponse: "Ignored"}, + {Label: "Receive Sent Event", URL: eventURL, Data: sentEvent, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedExternalID: Sp("xx12345"), ExpectedMsgStatus: Sp("S")}, + {Label: "Receive Delivered Event", URL: eventURL, Data: deliveredEvent, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedExternalID: Sp("xx12345"), ExpectedMsgStatus: Sp("D")}, + {Label: "Receive Failed Event", URL: eventURL, Data: failedEvent, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedExternalID: Sp("xx12345"), ExpectedMsgStatus: Sp("F")}, + {Label: "Receive Unknown Event", URL: eventURL, Data: unknownEvent, ExpectedStatus: 200, ExpectedResponse: "Ignored"}, + + {Label: "Receive Invalid JSON", URL: eventURL, Data: "not json", ExpectedStatus: 400, ExpectedResponse: "Error"}, + {Label: "Receive Missing Event Type", URL: eventURL, Data: missingEventType, ExpectedStatus: 400, ExpectedResponse: "Error"}, } var authenticatedTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: inboundURL, Data: validMsg, Headers: map[string]string{"Authorization": "Token sesame"}, - Status: 200, Response: "Accepted", - Text: Sp("hello world"), URN: Sp("tel:+250788383383"), - Date: Tp(time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC))}, + ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+250788383383"), + ExpectedDate: Tp(time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC))}, {Label: "Invalid Incoming Authorization", URL: inboundURL, Data: validMsg, Headers: map[string]string{"Authorization": "Token foo"}, - Status: 401, Response: "Unauthorized"}, + ExpectedStatus: 401, ExpectedResponse: "Unauthorized"}, {Label: "Receive Sent Event", URL: eventURL, Data: sentEvent, Headers: map[string]string{"Authorization": "Token sesame"}, - Status: 200, Response: "Accepted", - ExternalID: Sp("xx12345"), MsgStatus: Sp("S")}, + ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedExternalID: Sp("xx12345"), ExpectedMsgStatus: Sp("S")}, {Label: "Invalid Incoming Authorization", URL: eventURL, Data: sentEvent, Headers: map[string]string{"Authorization": "Token foo"}, - Status: 401, Response: "Unauthorized"}, + ExpectedStatus: 401, ExpectedResponse: "Unauthorized"}, } func TestHandler(t *testing.T) { diff --git a/handlers/kaleyra/kaleyra_test.go b/handlers/kaleyra/kaleyra_test.go index 6cf19bb90..6f51a8657 100644 --- a/handlers/kaleyra/kaleyra_test.go +++ b/handlers/kaleyra/kaleyra_test.go @@ -28,79 +28,79 @@ var testChannels = []courier.Channel{ var testCases = []ChannelHandleTestCase{ { - Label: "Receive Msg", - URL: receiveMsgURL + "?created_at=1603914166&type=text&from=14133881111&name=John%20Cruz&body=Hello%20World", - Name: Sp("John Cruz"), - URN: Sp("whatsapp:14133881111"), - Text: Sp("Hello World"), - Attachments: []string{}, - Status: 200, - Response: "Accepted", + Label: "Receive Msg", + URL: receiveMsgURL + "?created_at=1603914166&type=text&from=14133881111&name=John%20Cruz&body=Hello%20World", + ExpectedContactName: Sp("John Cruz"), + ExpectedURN: Sp("whatsapp:14133881111"), + ExpectedMsgText: Sp("Hello World"), + ExpectedAttachments: []string{}, + ExpectedStatus: 200, + ExpectedResponse: "Accepted", }, { - Label: "Receive Media", - URL: receiveMsgURL + "?created_at=1603914166&type=image&from=14133881111&name=John%20Cruz&media_url=https://link.to/image.jpg", - Name: Sp("John Cruz"), - URN: Sp("whatsapp:14133881111"), - Text: Sp(""), - Attachment: Sp("https://link.to/image.jpg"), - Status: 200, - Response: "Accepted", + Label: "Receive Media", + URL: receiveMsgURL + "?created_at=1603914166&type=image&from=14133881111&name=John%20Cruz&media_url=https://link.to/image.jpg", + ExpectedContactName: Sp("John Cruz"), + ExpectedURN: Sp("whatsapp:14133881111"), + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"https://link.to/image.jpg"}, + ExpectedStatus: 200, + ExpectedResponse: "Accepted", }, { - Label: "Receive Empty", - URL: receiveMsgURL + "?created_at=1603914166&type=text&from=14133881111&name=John%20Cruz", - Status: 400, - Response: "no text or media", + Label: "Receive Empty", + URL: receiveMsgURL + "?created_at=1603914166&type=text&from=14133881111&name=John%20Cruz", + ExpectedStatus: 400, + ExpectedResponse: "no text or media", }, { - Label: "Receive Invalid CreatedAt", - URL: receiveMsgURL + "?created_at=nottimestamp&type=text&from=14133881111&name=John%20Cruz&body=Hi", - Name: Sp("John Cruz"), - Status: 400, - Response: "invalid created_at", + Label: "Receive Invalid CreatedAt", + URL: receiveMsgURL + "?created_at=nottimestamp&type=text&from=14133881111&name=John%20Cruz&body=Hi", + ExpectedContactName: Sp("John Cruz"), + ExpectedStatus: 400, + ExpectedResponse: "invalid created_at", }, { - Label: "Receive Invalid Type", - URL: receiveMsgURL + "?created_at=1603914166&type=sticker&from=14133881111&name=John%20Cruz", - Status: 200, - Response: "unknown message type", + Label: "Receive Invalid Type", + URL: receiveMsgURL + "?created_at=1603914166&type=sticker&from=14133881111&name=John%20Cruz", + ExpectedStatus: 200, + ExpectedResponse: "unknown message type", }, { - Label: "Receive Invalid From", - URL: receiveMsgURL + "?created_at=1603914166&type=text&from=notnumber&name=John%20Cruz&body=Hi", - Name: Sp("John Cruz"), - Status: 400, - Response: "invalid whatsapp id", + Label: "Receive Invalid From", + URL: receiveMsgURL + "?created_at=1603914166&type=text&from=notnumber&name=John%20Cruz&body=Hi", + ExpectedContactName: Sp("John Cruz"), + ExpectedStatus: 400, + ExpectedResponse: "invalid whatsapp id", }, { - Label: "Receive Blank From", - URL: receiveMsgURL, - Status: 400, - Response: "field 'from' required", + Label: "Receive Blank From", + URL: receiveMsgURL, + ExpectedStatus: 400, + ExpectedResponse: "field 'from' required", }, { - Label: "Receive Valid Status", - URL: receiveStatusURL + "?id=58f86fab-85c5-4f7c-9b68-9c323248afc4%3A0&status=read", - ExternalID: Sp("58f86fab-85c5-4f7c-9b68-9c323248afc4:0"), - MsgStatus: Sp("D"), - Status: 200, - Response: `"type":"status"`, + Label: "Receive Valid Status", + URL: receiveStatusURL + "?id=58f86fab-85c5-4f7c-9b68-9c323248afc4%3A0&status=read", + ExpectedExternalID: Sp("58f86fab-85c5-4f7c-9b68-9c323248afc4:0"), + ExpectedMsgStatus: Sp("D"), + ExpectedStatus: 200, + ExpectedResponse: `"type":"status"`, }, { - Label: "Receive Invalid Status", - URL: receiveStatusURL + "?id=58f86fab-85c5-4f7c-9b68-9c323248afc4%3A0&status=deleted", - ExternalID: Sp("58f86fab-85c5-4f7c-9b68-9c323248afc4:0"), - MsgStatus: Sp("D"), - Status: 200, - Response: "unknown status", + Label: "Receive Invalid Status", + URL: receiveStatusURL + "?id=58f86fab-85c5-4f7c-9b68-9c323248afc4%3A0&status=deleted", + ExpectedExternalID: Sp("58f86fab-85c5-4f7c-9b68-9c323248afc4:0"), + ExpectedMsgStatus: Sp("D"), + ExpectedStatus: 200, + ExpectedResponse: "unknown status", }, { - Label: "Receive Blank status", - URL: receiveStatusURL, - ExternalID: Sp("58f86fab-85c5-4f7c-9b68-9c323248afc4:0"), - Status: 400, - Response: "field 'status' required", + Label: "Receive Blank status", + URL: receiveStatusURL, + ExpectedExternalID: Sp("58f86fab-85c5-4f7c-9b68-9c323248afc4:0"), + ExpectedStatus: 400, + ExpectedResponse: "field 'status' required", }, } diff --git a/handlers/kannel/kannel_test.go b/handlers/kannel/kannel_test.go index 8cb77c1d0..c130a6959 100644 --- a/handlers/kannel/kannel_test.go +++ b/handlers/kannel/kannel_test.go @@ -32,25 +32,25 @@ var ignoreChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729"), ExternalID: Sp("asdf-asdf"), Date: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, - {Label: "Receive KI Message", URL: receiveKIMessage, Data: "empty", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+68673076228"), ExternalID: Sp("asdf-asdf"), Date: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, - {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", Status: 200, Response: "Accepted", - Text: Sp(""), URN: Sp("tel:+2349067554729"), ExternalID: Sp("asdf-asdf"), Date: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", Status: 400, Response: "field 'sender' required"}, - {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Status No Params", URL: statusNoParams, Status: 400, Response: "field 'status' required"}, - {Label: "Status Invalid Status", URL: statusInvalidStatus, Status: 400, Response: "unknown status '66', must be one of 1,2,4,8,16"}, - {Label: "Status Valid", URL: statusWired, Status: 200, Response: `"status":"S"`}, + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedExternalID: Sp("asdf-asdf"), ExpectedDate: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, + {Label: "Receive KI Message", URL: receiveKIMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+68673076228"), ExpectedExternalID: Sp("asdf-asdf"), ExpectedDate: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, + {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+2349067554729"), ExpectedExternalID: Sp("asdf-asdf"), ExpectedDate: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, + {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'sender' required"}, + {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Status No Params", URL: statusNoParams, ExpectedStatus: 400, ExpectedResponse: "field 'status' required"}, + {Label: "Status Invalid Status", URL: statusInvalidStatus, ExpectedStatus: 400, ExpectedResponse: "unknown status '66', must be one of 1,2,4,8,16"}, + {Label: "Status Valid", URL: statusWired, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, } var ignoreTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729"), ExternalID: Sp("asdf-asdf"), Date: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, - {Label: "Write Status Delivered", URL: statusDelivered, Status: 200, Response: `"status":"D"`}, - {Label: "Ignore Status Wired", URL: statusWired, Status: 200, Response: `ignoring sent report`}, - {Label: "Ignore Status Sent", URL: statusSent, Status: 200, Response: `ignoring sent report`}, + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedExternalID: Sp("asdf-asdf"), ExpectedDate: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, + {Label: "Write Status Delivered", URL: statusDelivered, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`}, + {Label: "Ignore Status Wired", URL: statusWired, ExpectedStatus: 200, ExpectedResponse: `ignoring sent report`}, + {Label: "Ignore Status Sent", URL: statusSent, ExpectedStatus: 200, ExpectedResponse: `ignoring sent report`}, } func TestHandler(t *testing.T) { diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index 581cea581..f0076f193 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -257,37 +257,37 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, Status: 200, Response: "Accepted", - Text: Sp("Hello, world"), URN: Sp("line:uabcdefghij"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Hello, world"), ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessageLast, Status: 200, Response: "Accepted", - Text: Sp("Last event"), URN: Sp("line:uabcdefghij"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessageLast, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Last event"), ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Image Message", URL: receiveURL, Data: receiveValidImageMessage, Status: 200, Response: "Accepted", - Text: Sp(""), Attachment: Sp("https://api-data.line.me/v2/bot/message/100001/content"), URN: Sp("line:uabcdefghij"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive Valid Image Message", URL: receiveURL, Data: receiveValidImageMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Video Message", URL: receiveURL, Data: receiveValidVideoMessage, Status: 200, Response: "Accepted", - Text: Sp(""), Attachment: Sp("https://api-data.line.me/v2/bot/message/100001/content"), URN: Sp("line:uabcdefghij"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive Valid Video Message", URL: receiveURL, Data: receiveValidVideoMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Video External Message", URL: receiveURL, Data: receiveValidVideoExternalMessage, Status: 200, Response: "Accepted", - Text: Sp(""), Attachment: Sp("https://example.com/original.mp4"), URN: Sp("line:uabcdefghij"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive Valid Video External Message", URL: receiveURL, Data: receiveValidVideoExternalMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://example.com/original.mp4"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Audio Message", URL: receiveURL, Data: receiveValidAudioMessage, Status: 200, Response: "Accepted", - Text: Sp(""), Attachment: Sp("https://api-data.line.me/v2/bot/message/100001/content"), URN: Sp("line:uabcdefghij"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive Valid Audio Message", URL: receiveURL, Data: receiveValidAudioMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Receive Valid Location Message", URL: receiveURL, Data: receiveValidLocationMessage, Status: 200, Response: "Accepted", - Text: Sp("my location"), Attachment: Sp("geo:35.687574,139.729220"), URN: Sp("line:uabcdefghij"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + {Label: "Receive Valid Location Message", URL: receiveURL, Data: receiveValidLocationMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("my location"), ExpectedAttachments: []string{"geo:35.687574,139.729220"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), PrepRequest: addValidSignature}, - {Label: "Missing message", URL: receiveURL, Data: missingMessage, Status: 200, Response: "ignoring request, no message", + {Label: "Missing message", URL: receiveURL, Data: missingMessage, ExpectedStatus: 200, ExpectedResponse: "ignoring request, no message", PrepRequest: addValidSignature}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, Status: 400, Response: "invalid line id", + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "invalid line id", PrepRequest: addValidSignature}, - {Label: "No event request", URL: receiveURL, Data: noEvent, Status: 200, Response: "ignoring request, no message", + {Label: "No event request", URL: receiveURL, Data: noEvent, ExpectedStatus: 200, ExpectedResponse: "ignoring request, no message", PrepRequest: addValidSignature}, - {Label: "Receive Valid Message Invalid signature", URL: receiveURL, Data: receiveValidMessage, Status: 400, Response: "invalid request signature", + {Label: "Receive Valid Message Invalid signature", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 400, ExpectedResponse: "invalid request signature", PrepRequest: addInvalidSignature}, } diff --git a/handlers/m3tech/m3tech_test.go b/handlers/m3tech/m3tech_test.go index e76f32429..4e4be31e6 100644 --- a/handlers/m3tech/m3tech_test.go +++ b/handlers/m3tech/m3tech_test.go @@ -20,10 +20,10 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: " ", Status: 200, Response: "SMS Accepted", - Text: Sp("hello world"), URN: Sp("tel:+923161909799")}, - {Label: "Invalid URN", URL: receiveInvalidURN, Data: " ", Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Receive No From", URL: receiveMissingFrom, Data: " ", Status: 400, Response: "missing required field 'from'"}, + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: " ", ExpectedStatus: 200, ExpectedResponse: "SMS Accepted", + ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+923161909799")}, + {Label: "Invalid URN", URL: receiveInvalidURN, Data: " ", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Receive No From", URL: receiveMissingFrom, Data: " ", ExpectedStatus: 400, ExpectedResponse: "missing required field 'from'"}, } func TestHandler(t *testing.T) { diff --git a/handlers/macrokiosk/macrokiosk_test.go b/handlers/macrokiosk/macrokiosk_test.go index e71cc2ab8..5cf651a90 100644 --- a/handlers/macrokiosk/macrokiosk_test.go +++ b/handlers/macrokiosk/macrokiosk_test.go @@ -31,23 +31,23 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, Status: 200, Response: "-1", - Text: Sp("Hello"), URN: Sp("tel:+60124361111"), Date: Tp(time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC)), - ExternalID: Sp("abc1234")}, - {Label: "Receive Valid via GET", URL: receiveURL + "?" + validReceive, Status: 200, Response: "-1", - Text: Sp("Hello"), URN: Sp("tel:+60124361111"), Date: Tp(time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC)), - ExternalID: Sp("abc1234")}, - {Label: "Receive Valid", URL: receiveURL, Data: validLongcodeReceive, Status: 200, Response: "-1", - Text: Sp("Hello"), URN: Sp("tel:+60124361111"), Date: Tp(time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC)), - ExternalID: Sp("abc1234")}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Missing Params", URL: receiveURL, Data: missingParamsReceive, Status: 400, Response: "missing shortcode, longcode, from or msisdn parameters"}, - {Label: "Invalid Params", URL: receiveURL, Data: invalidParamsReceive, Status: 400, Response: "missing shortcode, longcode, from or msisdn parameters"}, - {Label: "Invalid Address Params", URL: receiveURL, Data: invalidAddress, Status: 400, Response: "invalid to number [1515], expecting [2020]"}, + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "-1", + ExpectedMsgText: Sp("Hello"), ExpectedURN: Sp("tel:+60124361111"), ExpectedDate: Tp(time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC)), + ExpectedExternalID: Sp("abc1234")}, + {Label: "Receive Valid via GET", URL: receiveURL + "?" + validReceive, ExpectedStatus: 200, ExpectedResponse: "-1", + ExpectedMsgText: Sp("Hello"), ExpectedURN: Sp("tel:+60124361111"), ExpectedDate: Tp(time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC)), + ExpectedExternalID: Sp("abc1234")}, + {Label: "Receive Valid", URL: receiveURL, Data: validLongcodeReceive, ExpectedStatus: 200, ExpectedResponse: "-1", + ExpectedMsgText: Sp("Hello"), ExpectedURN: Sp("tel:+60124361111"), ExpectedDate: Tp(time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC)), + ExpectedExternalID: Sp("abc1234")}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Missing Params", URL: receiveURL, Data: missingParamsReceive, ExpectedStatus: 400, ExpectedResponse: "missing shortcode, longcode, from or msisdn parameters"}, + {Label: "Invalid Params", URL: receiveURL, Data: invalidParamsReceive, ExpectedStatus: 400, ExpectedResponse: "missing shortcode, longcode, from or msisdn parameters"}, + {Label: "Invalid Address Params", URL: receiveURL, Data: invalidAddress, ExpectedStatus: 400, ExpectedResponse: "invalid to number [1515], expecting [2020]"}, - {Label: "Valid Status", URL: statusURL, Data: validStatus, Status: 200, Response: `"status":"S"`}, - {Label: "Wired Status", URL: statusURL, Data: processingStatus, Status: 200, Response: `"status":"W"`}, - {Label: "Unknown Status", URL: statusURL, Data: unknownStatus, Status: 200, Response: `ignoring unknown status 'UNKNOWN'`}, + {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, + {Label: "Wired Status", URL: statusURL, Data: processingStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"W"`}, + {Label: "Unknown Status", URL: statusURL, Data: unknownStatus, ExpectedStatus: 200, ExpectedResponse: `ignoring unknown status 'UNKNOWN'`}, } func TestHandler(t *testing.T) { diff --git a/handlers/mblox/mblox_test.go b/handlers/mblox/mblox_test.go index b9be3f89a..768d181ef 100644 --- a/handlers/mblox/mblox_test.go +++ b/handlers/mblox/mblox_test.go @@ -62,16 +62,16 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Hello World"), URN: Sp("tel:+12067799294"), Date: Tp(time.Date(2016, 3, 30, 19, 33, 06, 643000000, time.UTC)), - ExternalID: Sp("OzQ5UqIOdoY8")}, + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("tel:+12067799294"), ExpectedDate: Tp(time.Date(2016, 3, 30, 19, 33, 06, 643000000, time.UTC)), + ExpectedExternalID: Sp("OzQ5UqIOdoY8")}, - {Label: "Receive Missing Params", URL: receiveURL, Data: missingParamsRecieve, Status: 400, Response: "missing one of 'id', 'from', 'to', 'body' or 'received_at' in request body"}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, Status: 400, Response: "phone number supplied is not a number"}, + {Label: "Receive Missing Params", URL: receiveURL, Data: missingParamsRecieve, ExpectedStatus: 400, ExpectedResponse: "missing one of 'id', 'from', 'to', 'body' or 'received_at' in request body"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Status Valid", URL: receiveURL, Data: validStatus, Status: 200, Response: `"status":"D"`}, - {Label: "Status Unknown", URL: receiveURL, Data: unknownStatus, Status: 400, Response: `unknown status 'INVALID'`}, - {Label: "Status Missing Batch ID", URL: receiveURL, Data: missingBatchID, Status: 400, Response: "missing one of 'batch_id' or 'status' in request body"}, + {Label: "Status Valid", URL: receiveURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`}, + {Label: "Status Unknown", URL: receiveURL, Data: unknownStatus, ExpectedStatus: 400, ExpectedResponse: `unknown status 'INVALID'`}, + {Label: "Status Missing Batch ID", URL: receiveURL, Data: missingBatchID, ExpectedStatus: 400, ExpectedResponse: "missing one of 'batch_id' or 'status' in request body"}, } func TestHandler(t *testing.T) { diff --git a/handlers/messangi/messangi_test.go b/handlers/messangi/messangi_test.go index b56438d9d..8172e2d7c 100644 --- a/handlers/messangi/messangi_test.go +++ b/handlers/messangi/messangi_test.go @@ -21,9 +21,9 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Msg"), URN: Sp("tel:+18765422035")}, - {Label: "Receive Missing Number", URL: receiveURL, Data: missingNumber, Status: 400, Response: "required field 'mobile'"}, + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+18765422035")}, + {Label: "Receive Missing Number", URL: receiveURL, Data: missingNumber, ExpectedStatus: 400, ExpectedResponse: "required field 'mobile'"}, } func TestHandler(t *testing.T) { diff --git a/handlers/mtarget/mtarget_test.go b/handlers/mtarget/mtarget_test.go index 4ccc45324..3a1169ddd 100644 --- a/handlers/mtarget/mtarget_test.go +++ b/handlers/mtarget/mtarget_test.go @@ -32,22 +32,22 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, Status: 200, Response: "Accepted", - Text: Sp("hello world"), URN: Sp("tel:+923161909799")}, - {Label: "Invalid URN", URL: receiveURL, Data: receiveInvalidURN, Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Receive Stop", URL: receiveURL, Data: receiveStop, Status: 200, Response: "Accepted", - URN: Sp("tel:+923161909799"), ChannelEvent: Sp("stop_contact")}, - {Label: "Receive Missing From", URL: receiveURL, Data: receiveMissingFrom, Status: 400, Response: "missing required field 'Msisdn'"}, - - {Label: "Receive Part 2", URL: receiveURL, Data: receivePart2, Status: 200, Response: "received"}, - {Label: "Receive Part 1", URL: receiveURL, Data: receivePart1, Status: 200, Response: "Accepted", - Text: Sp("hello world"), URN: Sp("tel:+923161909799")}, - - {Label: "Status Delivered", URL: statusURL, Data: statusDelivered, Status: 200, Response: "Accepted", - ExternalID: Sp("12a7ee90-50ce-11e7-80ae-00000a0a643c"), MsgStatus: Sp("D")}, - {Label: "Status Failed", URL: statusURL, Data: statusFailed, Status: 200, Response: "Accepted", - ExternalID: Sp("12a7ee90-50ce-11e7-80ae-00000a0a643c"), MsgStatus: Sp("F")}, - {Label: "Status Missing ID", URL: statusURL, Data: statusMissingID, Status: 400, Response: "missing required field 'MsgId'"}, + {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+923161909799")}, + {Label: "Invalid URN", URL: receiveURL, Data: receiveInvalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Receive Stop", URL: receiveURL, Data: receiveStop, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedURN: Sp("tel:+923161909799"), ChannelEvent: Sp("stop_contact")}, + {Label: "Receive Missing From", URL: receiveURL, Data: receiveMissingFrom, ExpectedStatus: 400, ExpectedResponse: "missing required field 'Msisdn'"}, + + {Label: "Receive Part 2", URL: receiveURL, Data: receivePart2, ExpectedStatus: 200, ExpectedResponse: "received"}, + {Label: "Receive Part 1", URL: receiveURL, Data: receivePart1, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+923161909799")}, + + {Label: "Status Delivered", URL: statusURL, Data: statusDelivered, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedExternalID: Sp("12a7ee90-50ce-11e7-80ae-00000a0a643c"), ExpectedMsgStatus: Sp("D")}, + {Label: "Status Failed", URL: statusURL, Data: statusFailed, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedExternalID: Sp("12a7ee90-50ce-11e7-80ae-00000a0a643c"), ExpectedMsgStatus: Sp("F")}, + {Label: "Status Missing ID", URL: statusURL, Data: statusMissingID, ExpectedStatus: 400, ExpectedResponse: "missing required field 'MsgId'"}, } func TestHandler(t *testing.T) { diff --git a/handlers/nexmo/nexmo_test.go b/handlers/nexmo/nexmo_test.go index 305b18622..0e5b2fb4f 100644 --- a/handlers/nexmo/nexmo_test.go +++ b/handlers/nexmo/nexmo_test.go @@ -30,20 +30,20 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Valid Receive", URL: receiveValidMessage, Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729")}, - {Label: "Invalid URN", URL: receiveInvalidURN, Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Valid Receive Post", URL: receiveURL, Status: 200, Response: "Accepted", Data: receiveValidMessageBody, - Text: Sp("Join"), URN: Sp("tel:+2349067554729")}, - {Label: "Receive URL check", URL: receiveURL, Status: 200, Response: "no to parameter, ignored"}, - {Label: "Status URL check", URL: statusURL, Status: 200, Response: "no messageId parameter, ignored"}, + {Label: "Valid Receive", URL: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + {Label: "Invalid URN", URL: receiveInvalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Valid Receive Post", URL: receiveURL, ExpectedStatus: 200, ExpectedResponse: "Accepted", Data: receiveValidMessageBody, + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + {Label: "Receive URL check", URL: receiveURL, ExpectedStatus: 200, ExpectedResponse: "no to parameter, ignored"}, + {Label: "Status URL check", URL: statusURL, ExpectedStatus: 200, ExpectedResponse: "no messageId parameter, ignored"}, - {Label: "Status delivered", URL: statusDelivered, Status: 200, Response: `"status":"D"`, ExternalID: Sp("external1")}, - {Label: "Status expired", URL: statusExpired, Status: 200, Response: `"status":"F"`, ExternalID: Sp("external1")}, - {Label: "Status failed", URL: statusFailed, Status: 200, Response: `"status":"F"`, ExternalID: Sp("external1")}, - {Label: "Status accepted", URL: statusAccepted, Status: 200, Response: `"status":"S"`, ExternalID: Sp("external1")}, - {Label: "Status buffered", URL: statusBuffered, Status: 200, Response: `"status":"S"`, ExternalID: Sp("external1")}, - {Label: "Status unexpected", URL: statusUnexpected, Status: 200, Response: "ignoring unknown status report", ExternalID: Sp("external1")}, + {Label: "Status delivered", URL: statusDelivered, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("external1")}, + {Label: "Status expired", URL: statusExpired, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, ExpectedExternalID: Sp("external1")}, + {Label: "Status failed", URL: statusFailed, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, ExpectedExternalID: Sp("external1")}, + {Label: "Status accepted", URL: statusAccepted, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`, ExpectedExternalID: Sp("external1")}, + {Label: "Status buffered", URL: statusBuffered, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`, ExpectedExternalID: Sp("external1")}, + {Label: "Status unexpected", URL: statusUnexpected, ExpectedStatus: 200, ExpectedResponse: "ignoring unknown status report", ExpectedExternalID: Sp("external1")}, } func TestHandler(t *testing.T) { diff --git a/handlers/novo/novo_test.go b/handlers/novo/novo_test.go index d75516796..9349fecaa 100644 --- a/handlers/novo/novo_test.go +++ b/handlers/novo/novo_test.go @@ -25,12 +25,12 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Msg"), URN: Sp("tel:+18686846481"), Headers: map[string]string{"Authorization": "sesame"}}, - {Label: "Receive Missing Number", URL: receiveURL, Data: missingNumber, Status: 400, Response: "required field 'from'", + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+18686846481"), Headers: map[string]string{"Authorization": "sesame"}}, + {Label: "Receive Missing Number", URL: receiveURL, Data: missingNumber, ExpectedStatus: 400, ExpectedResponse: "required field 'from'", Headers: map[string]string{"Authorization": "sesame"}}, - {Label: "Receive Missing Authorization", URL: receiveURL, Data: validReceive, Status: 401, Response: "invalid Authorization header", - Text: Sp("Msg"), URN: Sp("tel:+18686846481")}, + {Label: "Receive Missing Authorization", URL: receiveURL, Data: validReceive, ExpectedStatus: 401, ExpectedResponse: "invalid Authorization header", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+18686846481")}, } func TestHandler(t *testing.T) { diff --git a/handlers/playmobile/playmobile_test.go b/handlers/playmobile/playmobile_test.go index 04d73f60c..873464cf4 100644 --- a/handlers/playmobile/playmobile_test.go +++ b/handlers/playmobile/playmobile_test.go @@ -88,39 +88,39 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid", - URL: receiveURL, - Data: validReceive, - Response: "Accepted", - Status: 200, - Text: Sp("SMS Response Accepted"), - URN: Sp("tel:+998999999999")}, + URL: receiveURL, + Data: validReceive, + ExpectedResponse: "Accepted", + ExpectedStatus: 200, + ExpectedMsgText: Sp("SMS Response Accepted"), + ExpectedURN: Sp("tel:+998999999999")}, {Label: "Receive Missing MSISDN", - URL: receiveURL, - Data: invalidReceive, - Response: "missing required fields msidsn or id", - Status: 400}, + URL: receiveURL, + Data: invalidReceive, + ExpectedResponse: "missing required fields msidsn or id", + ExpectedStatus: 400}, {Label: "No Messages", - URL: receiveURL, - Data: noMessages, - Response: "no messages, ignored", - Status: 200}, + URL: receiveURL, + Data: noMessages, + ExpectedResponse: "no messages, ignored", + ExpectedStatus: 200}, {Label: "Invalid XML", - URL: receiveURL, - Data: invalidXML, - Response: "", - Status: 405}, + URL: receiveURL, + Data: invalidXML, + ExpectedResponse: "", + ExpectedStatus: 405}, {Label: "Receive With Prefix", - URL: receiveURL, - Data: receiveWithPrefix, - Response: "Accepted", - Status: 200, - Text: Sp("SMS Response Accepted"), - URN: Sp("tel:+998999999999")}, + URL: receiveURL, + Data: receiveWithPrefix, + ExpectedResponse: "Accepted", + ExpectedStatus: 200, + ExpectedMsgText: Sp("SMS Response Accepted"), + ExpectedURN: Sp("tel:+998999999999")}, {Label: "Receive With Prefix Only", - URL: receiveURL, - Data: receiveWithPrefixOnly, - Response: "no text", - Status: 400}, + URL: receiveURL, + Data: receiveWithPrefixOnly, + ExpectedResponse: "no text", + ExpectedStatus: 400}, } func TestHandler(t *testing.T) { diff --git a/handlers/plivo/plivo_test.go b/handlers/plivo/plivo_test.go index 5d4257cc4..bcc39139f 100644 --- a/handlers/plivo/plivo_test.go +++ b/handlers/plivo/plivo_test.go @@ -29,16 +29,16 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Hello"), URN: Sp("tel:+60124361111"), ExternalID: Sp("abc1234")}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Invalid Address Params", URL: receiveURL, Data: invalidAddress, Status: 400, Response: "invalid to number [1515], expecting [2020]"}, - {Label: "Missing Params", URL: receiveURL, Data: missingParams, Status: 400, Response: "Field validation for 'To' failed"}, + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Hello"), ExpectedURN: Sp("tel:+60124361111"), ExpectedExternalID: Sp("abc1234")}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Invalid Address Params", URL: receiveURL, Data: invalidAddress, ExpectedStatus: 400, ExpectedResponse: "invalid to number [1515], expecting [2020]"}, + {Label: "Missing Params", URL: receiveURL, Data: missingParams, ExpectedStatus: 400, ExpectedResponse: "Field validation for 'To' failed"}, - {Label: "Valid Status", URL: statusURL, Data: validStatus, Status: 200, Response: `"status":"D"`}, - {Label: "Sent Status", URL: statusURL, Data: validSentStatus, Status: 200, Response: `"status":"S"`}, - {Label: "Invalid Status Address", URL: statusURL, Data: invalidStatusAddress, Status: 400, Response: "invalid to number [1515], expecting [2020]"}, - {Label: "Unkown Status", URL: statusURL, Data: unknownStatus, Status: 200, Response: `ignoring unknown status 'UNKNOWN'`}, + {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`}, + {Label: "Sent Status", URL: statusURL, Data: validSentStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, + {Label: "Invalid Status Address", URL: statusURL, Data: invalidStatusAddress, ExpectedStatus: 400, ExpectedResponse: "invalid to number [1515], expecting [2020]"}, + {Label: "Unkown Status", URL: statusURL, Data: unknownStatus, ExpectedStatus: 200, ExpectedResponse: `ignoring unknown status 'UNKNOWN'`}, } func TestHandler(t *testing.T) { diff --git a/handlers/rocketchat/rocketchat_test.go b/handlers/rocketchat/rocketchat_test.go index d24048f78..f0247a3ea 100644 --- a/handlers/rocketchat/rocketchat_test.go +++ b/handlers/rocketchat/rocketchat_test.go @@ -56,11 +56,11 @@ var testCases = []handlers.ChannelHandleTestCase{ Headers: map[string]string{ "Authorization": "Token 123456789", }, - Data: helloMsg, - URN: handlers.Sp("rocketchat:direct:john.doe#john.doe"), - Text: handlers.Sp("Hello World"), - Status: 200, - Response: "Accepted", + Data: helloMsg, + ExpectedURN: handlers.Sp("rocketchat:direct:john.doe#john.doe"), + ExpectedMsgText: handlers.Sp("Hello World"), + ExpectedStatus: 200, + ExpectedResponse: "Accepted", }, { Label: "Receive Attachment Msg", @@ -68,11 +68,11 @@ var testCases = []handlers.ChannelHandleTestCase{ Headers: map[string]string{ "Authorization": "Token 123456789", }, - Data: attachmentMsg, - URN: handlers.Sp("rocketchat:livechat:onrMgdKbpX9Qqtvoi"), - Attachment: handlers.Sp("https://link.to/image.jpg"), - Status: 200, - Response: "Accepted", + Data: attachmentMsg, + ExpectedURN: handlers.Sp("rocketchat:livechat:onrMgdKbpX9Qqtvoi"), + ExpectedAttachments: []string{"https://link.to/image.jpg"}, + ExpectedStatus: 200, + ExpectedResponse: "Accepted", }, { Label: "Don't Receive Empty Msg", @@ -80,9 +80,9 @@ var testCases = []handlers.ChannelHandleTestCase{ Headers: map[string]string{ "Authorization": "Token 123456789", }, - Data: emptyMsg, - Status: 400, - Response: "no text or attachment", + Data: emptyMsg, + ExpectedStatus: 400, + ExpectedResponse: "no text or attachment", }, { Label: "Invalid Authorization", @@ -90,9 +90,9 @@ var testCases = []handlers.ChannelHandleTestCase{ Headers: map[string]string{ "Authorization": "123456789", }, - Data: emptyMsg, - Status: 401, - Response: "invalid Authorization header", + Data: emptyMsg, + ExpectedStatus: 401, + ExpectedResponse: "invalid Authorization header", }, } diff --git a/handlers/shaqodoon/shaqodoon_test.go b/handlers/shaqodoon/shaqodoon_test.go index decbead78..c960bece7 100644 --- a/handlers/shaqodoon/shaqodoon_test.go +++ b/handlers/shaqodoon/shaqodoon_test.go @@ -27,20 +27,20 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729")}, - {Label: "Receive Badly Escaped", URL: receiveBadlyEscaped, Data: "empty", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+252999999999")}, - {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", Status: 200, Response: "Accepted", - Text: Sp(""), URN: Sp("tel:+2349067554729")}, - {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "empty", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729"), Date: Tp(time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC))}, - {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "empty", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729"), Date: Tp(time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC))}, - {Label: "Receive invalid URN", URL: receiveInvalidURN, Data: "empty", Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", Status: 400, Response: "field 'from' required"}, - {Label: "Receive No Sender", URL: receiveNoSender, Data: "empty", Status: 400, Response: "field 'from' required"}, - {Label: "Receive Invalid Date", URL: receiveInvalidDate, Data: "empty", Status: 400, Response: "invalid date format, must be RFC 3339"}, + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + {Label: "Receive Badly Escaped", URL: receiveBadlyEscaped, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+252999999999")}, + {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+2349067554729")}, + {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: Tp(time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC))}, + {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: Tp(time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC))}, + {Label: "Receive invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'from' required"}, + {Label: "Receive No Sender", URL: receiveNoSender, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'from' required"}, + {Label: "Receive Invalid Date", URL: receiveInvalidDate, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "invalid date format, must be RFC 3339"}, } func TestHandler(t *testing.T) { diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 531293bf5..1c2fd05cf 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -129,51 +129,50 @@ func setSendUrl(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var handleTestCases = []ChannelHandleTestCase{ { - Label: "Receive Hello Msg", - URL: receiveURL, - Headers: map[string]string{}, - Data: helloMsg, - URN: Sp("slack:U0123ABCDEF"), - Text: Sp("Hello World!"), - Status: 200, - Response: "Accepted", - ExternalID: Sp("Ev0PV52K21"), + Label: "Receive Hello Msg", + URL: receiveURL, + Headers: map[string]string{}, + Data: helloMsg, + ExpectedURN: Sp("slack:U0123ABCDEF"), + ExpectedMsgText: Sp("Hello World!"), + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedExternalID: Sp("Ev0PV52K21"), }, { - Label: "Receive image file", - URL: receiveURL, - Headers: map[string]string{}, - Data: imageFileMsg, - Attachment: Sp("https://files.slack.com/files-pri/T03CN5KTA6S-F03GTH43SSF/download/batata.jpg?pub_secret=39fcf577f2"), - URN: Sp("slack:U0123ABCDEF"), - Text: Sp(""), - Status: 200, - Response: "Accepted", - ExternalID: Sp("Ev0PV52K21"), + Label: "Receive image file", + URL: receiveURL, + Headers: map[string]string{}, + Data: imageFileMsg, + ExpectedAttachments: []string{"https://files.slack.com/files-pri/T03CN5KTA6S-F03GTH43SSF/download/batata.jpg?pub_secret=39fcf577f2"}, + ExpectedURN: Sp("slack:U0123ABCDEF"), + ExpectedMsgText: Sp(""), + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedExternalID: Sp("Ev0PV52K21"), }, { - Label: "Receive audio file", - URL: receiveURL, - Headers: map[string]string{}, - Data: audioFileMsg, - Attachment: Sp("https://files.slack.com/files-pri/T03CN5KTA6S-F03GWURCZL4/download/here_we_go_again.mp3?pub_secret=471020b300"), - URN: Sp("slack:U0123ABCDEF"), - Text: Sp(""), - Status: 200, - Response: "Accepted", - ExternalID: Sp("Ev0PV52K21"), + Label: "Receive audio file", + URL: receiveURL, + Headers: map[string]string{}, + Data: audioFileMsg, + ExpectedAttachments: []string{"https://files.slack.com/files-pri/T03CN5KTA6S-F03GWURCZL4/download/here_we_go_again.mp3?pub_secret=471020b300"}, + ExpectedURN: Sp("slack:U0123ABCDEF"), + ExpectedMsgText: Sp(""), + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedExternalID: Sp("Ev0PV52K21"), }, { - Label: "Receive video file (not allowed)", - URL: receiveURL, - Headers: map[string]string{}, - Data: videoFileMsg, - Attachment: nil, - URN: Sp("slack:U0123ABCDEF"), - Text: Sp(""), - Status: 200, - Response: "Accepted", - ExternalID: Sp("Ev0PV52K21"), + Label: "Receive video file (not allowed)", + URL: receiveURL, + Headers: map[string]string{}, + Data: videoFileMsg, + ExpectedURN: Sp("slack:U0123ABCDEF"), + ExpectedMsgText: Sp(""), + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedExternalID: Sp("Ev0PV52K21"), }, } @@ -265,12 +264,12 @@ func TestSendFiles(t *testing.T) { func TestVerification(t *testing.T) { RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ - {Label: "Valid token", URL: receiveURL, Status: 200, - Data: `{"token":"one-long-verification-token","challenge":"challenge123","type":"url_verification"}`, - Headers: map[string]string{"content-type": "text/plain"}, - Response: "challenge123", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + {Label: "Valid token", URL: receiveURL, ExpectedStatus: 200, + Data: `{"token":"one-long-verification-token","challenge":"challenge123","type":"url_verification"}`, + Headers: map[string]string{"content-type": "text/plain"}, + ExpectedResponse: "challenge123", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, }, - {Label: "Invalid token", URL: receiveURL, Status: 403, + {Label: "Invalid token", URL: receiveURL, ExpectedStatus: 403, Data: `{"token":"abc321","challenge":"challenge123","type":"url_verification"}`, Headers: map[string]string{"content-type": "text/plain"}, }, diff --git a/handlers/smscentral/smscentral_test.go b/handlers/smscentral/smscentral_test.go index 72d886932..3ec54b50b 100644 --- a/handlers/smscentral/smscentral_test.go +++ b/handlers/smscentral/smscentral_test.go @@ -23,13 +23,13 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729")}, - {Label: "Receive No Message", URL: receiveURL, Data: receiveNoMessage, Status: 200, Response: "Accepted", - Text: Sp(""), URN: Sp("tel:+2349067554729")}, - {Label: "Receive invalid URN", URL: receiveURL, Data: invalidURN, Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Receive No Params", URL: receiveURL, Data: receiveNoParams, Status: 400, Response: "field 'mobile' required"}, - {Label: "Receive No Sender", URL: receiveURL, Data: receiveNoSender, Status: 400, Response: "field 'mobile' required"}, + {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + {Label: "Receive No Message", URL: receiveURL, Data: receiveNoMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+2349067554729")}, + {Label: "Receive invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Receive No Params", URL: receiveURL, Data: receiveNoParams, ExpectedStatus: 400, ExpectedResponse: "field 'mobile' required"}, + {Label: "Receive No Sender", URL: receiveURL, Data: receiveNoSender, ExpectedStatus: 400, ExpectedResponse: "field 'mobile' required"}, } func TestHandler(t *testing.T) { diff --git a/handlers/start/start_test.go b/handlers/start/start_test.go index 118b36f7e..a9963f4c0 100644 --- a/handlers/start/start_test.go +++ b/handlers/start/start_test.go @@ -74,19 +74,19 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, Status: 200, Response: "Accepted", - Text: Sp("Hello World"), URN: Sp("tel:+250788123123"), Date: Tp(time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC))}, - {Label: "Receive Valid Encoded", URL: receiveURL, Data: validReceiveEncoded, Status: 200, Response: "Accepted", - Text: Sp("Кохання"), URN: Sp("tel:+380501529999"), Date: Tp(time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC))}, - {Label: "Receive Valid with empty Text", URL: receiveURL, Data: validReceiveEmptyText, Status: 200, Response: "Accepted", - Text: Sp(""), URN: Sp("tel:+250788123123")}, - {Label: "Receive Valid missing body", URL: receiveURL, Data: validMissingBody, Status: 200, Response: "Accepted", - Text: Sp(""), URN: Sp("tel:+250788123123")}, - {Label: "Receive invalidURN", URL: receiveURL, Data: invalidURNReceive, Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Receive missing Request ID", URL: receiveURL, Data: missingRequestID, Status: 400, Response: "Error"}, - {Label: "Receive missing From", URL: receiveURL, Data: missingFrom, Status: 400, Response: "Error"}, - {Label: "Receive missing To", URL: receiveURL, Data: missingTo, Status: 400, Response: "Error"}, - {Label: "Invalid XML", URL: receiveURL, Data: notXML, Status: 400, Response: "Error"}, + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("tel:+250788123123"), ExpectedDate: Tp(time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC))}, + {Label: "Receive Valid Encoded", URL: receiveURL, Data: validReceiveEncoded, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Кохання"), ExpectedURN: Sp("tel:+380501529999"), ExpectedDate: Tp(time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC))}, + {Label: "Receive Valid with empty Text", URL: receiveURL, Data: validReceiveEmptyText, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+250788123123")}, + {Label: "Receive Valid missing body", URL: receiveURL, Data: validMissingBody, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+250788123123")}, + {Label: "Receive invalidURN", URL: receiveURL, Data: invalidURNReceive, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Receive missing Request ID", URL: receiveURL, Data: missingRequestID, ExpectedStatus: 400, ExpectedResponse: "Error"}, + {Label: "Receive missing From", URL: receiveURL, Data: missingFrom, ExpectedStatus: 400, ExpectedResponse: "Error"}, + {Label: "Receive missing To", URL: receiveURL, Data: missingTo, ExpectedStatus: 400, ExpectedResponse: "Error"}, + {Label: "Invalid XML", URL: receiveURL, Data: notXML, ExpectedStatus: 400, ExpectedResponse: "Error"}, } func TestHandler(t *testing.T) { diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index 2969eb41a..07801930f 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -452,49 +452,49 @@ var contactMsg = ` }` var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: helloMsg, Status: 200, Response: "Accepted", - Name: Sp("Nic Pottier"), Text: Sp("Hello World"), URN: Sp("telegram:3527065#nicpottier"), ExternalID: Sp("41"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + {Label: "Receive Valid Message", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, - {Label: "Receive Start Message", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: startMsg, Status: 200, Response: "Accepted", - Name: Sp("Nic Pottier"), ChannelEvent: Sp(string(courier.NewConversation)), URN: Sp("telegram:3527065#nicpottier"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + {Label: "Receive Start Message", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: startMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), ChannelEvent: Sp(string(courier.NewConversation)), ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, - {Label: "Receive No Params", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: emptyMsg, Status: 200, Response: "Ignoring"}, + {Label: "Receive No Params", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: emptyMsg, ExpectedStatus: 200, ExpectedResponse: "Ignoring"}, - {Label: "Receive Invalid JSON", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: "foo", Status: 400, Response: "unable to parse"}, + {Label: "Receive Invalid JSON", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: "foo", ExpectedStatus: 400, ExpectedResponse: "unable to parse"}, - {Label: "Receive Sticker", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: stickerMsg, Status: 200, Response: "Accepted", - Name: Sp("Nic Pottier"), Text: Sp(""), Attachment: Sp("/file/bota123/sticker.jpg"), URN: Sp("telegram:3527065"), ExternalID: Sp("44"), Date: Tp(time.Date(2016, 1, 30, 2, 07, 48, 0, time.UTC))}, + {Label: "Receive Sticker", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: stickerMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/sticker.jpg"}, ExpectedURN: Sp("telegram:3527065"), ExpectedExternalID: Sp("44"), ExpectedDate: Tp(time.Date(2016, 1, 30, 2, 07, 48, 0, time.UTC))}, - {Label: "Receive Photo", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: photoMsg, Status: 200, Response: "Accepted", - Name: Sp("Nic Pottier"), Text: Sp("Photo Caption"), Attachment: Sp("/file/bota123/photo.jpg"), URN: Sp("telegram:3527065#nicpottier"), ExternalID: Sp("85"), Date: Tp(time.Date(2017, 5, 3, 20, 28, 38, 0, time.UTC))}, + {Label: "Receive Photo", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: photoMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Photo Caption"), ExpectedAttachments: []string{"/file/bota123/photo.jpg"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("85"), ExpectedDate: Tp(time.Date(2017, 5, 3, 20, 28, 38, 0, time.UTC))}, - {Label: "Receive Video", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: videoMsg, Status: 200, Response: "Accepted", - Name: Sp("Nic Pottier"), Text: Sp(""), Attachment: Sp("/file/bota123/video.jpg"), URN: Sp("telegram:3527065#nicpottier"), ExternalID: Sp("86"), Date: Tp(time.Date(2017, 5, 3, 20, 29, 24, 0, time.UTC))}, + {Label: "Receive Video", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: videoMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/video.jpg"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("86"), ExpectedDate: Tp(time.Date(2017, 5, 3, 20, 29, 24, 0, time.UTC))}, - {Label: "Receive Voice", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: voiceMsg, Status: 200, Response: "Accepted", - Name: Sp("Nic Pottier"), Text: Sp(""), Attachment: Sp("/file/bota123/voice.mp4"), URN: Sp("telegram:3527065#nicpottier"), ExternalID: Sp("91"), Date: Tp(time.Date(2017, 5, 3, 20, 50, 46, 0, time.UTC))}, + {Label: "Receive Voice", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: voiceMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/voice.mp4"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("91"), ExpectedDate: Tp(time.Date(2017, 5, 3, 20, 50, 46, 0, time.UTC))}, - {Label: "Receive Document", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: documentMsg, Status: 200, Response: "Accepted", - Name: Sp("Nic Pottier"), Text: Sp(""), Attachment: Sp("/file/bota123/document.xls"), URN: Sp("telegram:3527065#nicpottier"), ExternalID: Sp("92"), Date: Tp(time.Date(2017, 5, 3, 20, 58, 20, 0, time.UTC))}, + {Label: "Receive Document", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: documentMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/document.xls"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("92"), ExpectedDate: Tp(time.Date(2017, 5, 3, 20, 58, 20, 0, time.UTC))}, - {Label: "Receive Location", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: locationMsg, Status: 200, Response: "Accepted", - Name: Sp("Nic Pottier"), Text: Sp("-2.890287,-79.004333"), Attachment: Sp("geo:-2.890287,-79.004333"), URN: Sp("telegram:3527065#nicpottier"), ExternalID: Sp("94"), Date: Tp(time.Date(2017, 5, 3, 21, 00, 44, 0, time.UTC))}, + {Label: "Receive Location", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: locationMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("-2.890287,-79.004333"), ExpectedAttachments: []string{"geo:-2.890287,-79.004333"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("94"), ExpectedDate: Tp(time.Date(2017, 5, 3, 21, 00, 44, 0, time.UTC))}, - {Label: "Receive Venue", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: venueMsg, Status: 200, Response: "Accepted", - Name: Sp("Nic Pottier"), Text: Sp("Cuenca, Provincia del Azuay"), Attachment: Sp("geo:-2.898944,-79.006835"), URN: Sp("telegram:3527065#nicpottier"), ExternalID: Sp("95"), Date: Tp(time.Date(2017, 5, 3, 21, 05, 20, 0, time.UTC))}, + {Label: "Receive Venue", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: venueMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Cuenca, Provincia del Azuay"), ExpectedAttachments: []string{"geo:-2.898944,-79.006835"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("95"), ExpectedDate: Tp(time.Date(2017, 5, 3, 21, 05, 20, 0, time.UTC))}, - {Label: "Receive Contact", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: contactMsg, Status: 200, Response: "Accepted", - Name: Sp("Nic Pottier"), Text: Sp("Adolf Taxi (0788531373)"), URN: Sp("telegram:3527065#nicpottier"), ExternalID: Sp("96"), Date: Tp(time.Date(2017, 5, 3, 21, 9, 15, 0, time.UTC))}, + {Label: "Receive Contact", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: contactMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Adolf Taxi (0788531373)"), ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("96"), ExpectedDate: Tp(time.Date(2017, 5, 3, 21, 9, 15, 0, time.UTC))}, - {Label: "Receive Empty", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: emptyMsg, Status: 200, Response: "Ignoring"}, + {Label: "Receive Empty", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: emptyMsg, ExpectedStatus: 200, ExpectedResponse: "Ignoring"}, - {Label: "Receive Invalid FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: invalidFileID, Status: 200, Response: "unable to resolve file"}, + {Label: "Receive Invalid FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: invalidFileID, ExpectedStatus: 200, ExpectedResponse: "unable to resolve file"}, - {Label: "Receive NoOk FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: noOkFile, Status: 200, Response: "no 'ok' in response"}, + {Label: "Receive NoOk FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: noOkFile, ExpectedStatus: 200, ExpectedResponse: "no 'ok' in response"}, - {Label: "Receive NotOk FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: notOkFile, Status: 200, Response: "not present"}, + {Label: "Receive NotOk FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: notOkFile, ExpectedStatus: 200, ExpectedResponse: "not present"}, - {Label: "Receive No FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: noFile, Status: 200, Response: "result.file_path"}, + {Label: "Receive No FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: noFile, ExpectedStatus: 200, ExpectedResponse: "result.file_path"}, } func buildMockTelegramService(testCases []ChannelHandleTestCase) *httptest.Server { @@ -536,9 +536,11 @@ func buildMockTelegramService(testCases []ChannelHandleTestCase) *httptest.Serve apiURL = server.URL // update our tests media urls - for c := range testCases { - if testCases[c].Attachment != nil && !strings.HasPrefix(*testCases[c].Attachment, "geo") { - testCases[c].Attachment = Sp(fmt.Sprintf("%s%s", apiURL, *testCases[c].Attachment)) + for _, tc := range testCases { + for i := range tc.ExpectedAttachments { + if !strings.HasPrefix(tc.ExpectedAttachments[i], "geo:") { + tc.ExpectedAttachments[i] = fmt.Sprintf("%s%s", apiURL, tc.ExpectedAttachments[i]) + } } } diff --git a/handlers/telesom/telesom_test.go b/handlers/telesom/telesom_test.go index 1c0b8370e..c322ae7a6 100644 --- a/handlers/telesom/telesom_test.go +++ b/handlers/telesom/telesom_test.go @@ -23,17 +23,17 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729")}, - {Label: "Invalid URN", URL: invalidURN, Data: "", Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "", Status: 400, Response: "field 'mobile' required"}, - {Label: "Receive No Sender", URL: receiveNoSender, Data: "", Status: 400, Response: "field 'mobile' required"}, + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + {Label: "Invalid URN", URL: invalidURN, Data: "", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Receive No Params", URL: receiveNoParams, Data: "", ExpectedStatus: 400, ExpectedResponse: "field 'mobile' required"}, + {Label: "Receive No Sender", URL: receiveNoSender, Data: "", ExpectedStatus: 400, ExpectedResponse: "field 'mobile' required"}, - {Label: "Receive Valid Message", URL: receiveNoParams, Data: "mobile=%2B2349067554729&msg=Join", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729")}, - {Label: "Invalid URN", URL: receiveNoParams, Data: "mobile=MTN&msg=Join", Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", Status: 400, Response: "field 'mobile' required"}, - {Label: "Receive No Sender", URL: receiveNoParams, Data: "msg=Join", Status: 400, Response: "field 'mobile' required"}, + {Label: "Receive Valid Message", URL: receiveNoParams, Data: "mobile=%2B2349067554729&msg=Join", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + {Label: "Invalid URN", URL: receiveNoParams, Data: "mobile=MTN&msg=Join", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'mobile' required"}, + {Label: "Receive No Sender", URL: receiveNoParams, Data: "msg=Join", ExpectedStatus: 400, ExpectedResponse: "field 'mobile' required"}, } func TestHandler(t *testing.T) { diff --git a/handlers/test.go b/handlers/test.go index 0a5c01c44..d04f3d9e4 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -30,30 +30,27 @@ type RequestPrepFunc func(*http.Request) type ChannelHandleTestCase struct { Label string - URL string - Data string - Status int - Response string - Headers map[string]string - + URL string + Data string + Headers map[string]string MultipartFormFields map[string]string - Name *string - Text *string - URN *string - URNAuth *string - Attachment *string - Attachments []string - Date *time.Time + ExpectedStatus int + ExpectedResponse string - MsgStatus *string + ExpectedContactName *string + ExpectedMsgText *string + ExpectedURN *string + ExpectedURNAuth *string + ExpectedAttachments []string + ExpectedDate *time.Time + ExpectedMsgStatus *string + ExpectedExternalID *string + ExpectedMsgID int64 ChannelEvent *string ChannelEventExtra map[string]interface{} - ExternalID *string - ID int64 - NoQueueErrorCheck bool NoInvalidChannelCheck bool @@ -218,24 +215,24 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour mb.AddChannel(channel) handler.Initialize(s) - for _, testCase := range testCases { + for _, tc := range testCases { mockRRCount := 0 - t.Run(testCase.Label, func(t *testing.T) { + t.Run(tc.Label, func(t *testing.T) { require := require.New(t) - msg := mb.NewOutgoingMsg(channel, courier.NewMsgID(10), urns.URN(testCase.MsgURN), testCase.MsgText, testCase.MsgHighPriority, testCase.MsgQuickReplies, testCase.MsgTopic, testCase.MsgResponseToExternalID) + msg := mb.NewOutgoingMsg(channel, courier.NewMsgID(10), urns.URN(tc.MsgURN), tc.MsgText, tc.MsgHighPriority, tc.MsgQuickReplies, tc.MsgTopic, tc.MsgResponseToExternalID) - for _, a := range testCase.MsgAttachments { + for _, a := range tc.MsgAttachments { msg.WithAttachment(a) } - if testCase.MsgURNAuth != "" { - msg.WithURNAuth(testCase.MsgURNAuth) + if tc.MsgURNAuth != "" { + msg.WithURNAuth(tc.MsgURNAuth) } - if len(testCase.MsgMetadata) > 0 { - msg.WithMetadata(testCase.MsgMetadata) + if len(tc.MsgMetadata) > 0 { + msg.WithMetadata(tc.MsgMetadata) } - if testCase.MsgFlow != nil { - msg.WithFlow(testCase.MsgFlow) + if tc.MsgFlow != nil { + msg.WithFlow(tc.MsgFlow) } var testRequest *http.Request @@ -243,13 +240,13 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour body, _ := ioutil.ReadAll(r.Body) testRequest = httptest.NewRequest(r.Method, r.URL.String(), bytes.NewBuffer(body)) testRequest.Header = r.Header - if (len(testCase.MockResponses)) == 0 { - w.WriteHeader(testCase.MockResponseStatus) - w.Write([]byte(testCase.MockResponseBody)) + if (len(tc.MockResponses)) == 0 { + w.WriteHeader(tc.MockResponseStatus) + w.Write([]byte(tc.MockResponseBody)) } else { - require.Zero(testCase.MockResponseStatus, "ResponseStatus should not be used when using testcase.Responses") - require.Zero(testCase.MockResponseBody, "ResponseBody should not be used when using testcase.Responses") - for mockRequest, mockResponse := range testCase.MockResponses { + require.Zero(tc.MockResponseStatus, "ResponseStatus should not be used when using testcase.Responses") + require.Zero(tc.MockResponseBody, "ResponseBody should not be used when using testcase.Responses") + for mockRequest, mockResponse := range tc.MockResponses { bodyStr := string(body)[:] if mockRequest.Method == r.Method && mockRequest.Path == r.URL.Path && mockRequest.RawQuery == r.URL.RawQuery && (mockRequest.Body == bodyStr || (mockRequest.BodyContains != "" && strings.Contains(bodyStr, mockRequest.BodyContains))) { w.WriteHeader(mockResponse.Status) @@ -263,8 +260,8 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour defer server.Close() // call our prep function if we have one - if testCase.SendPrep != nil { - testCase.SendPrep(server, handler, channel, msg) + if tc.SendPrep != nil { + tc.SendPrep(server, handler, channel, msg) } logger := courier.NewChannelLoggerForSend(msg) @@ -278,65 +275,65 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour logger.Error(err) } - assert.Equal(t, testCase.ExpectedErrors, logger.Errors(), "unexpected errors logged") + assert.Equal(t, tc.ExpectedErrors, logger.Errors(), "unexpected errors logged") - if testCase.ExpectedRequestPath != "" { + if tc.ExpectedRequestPath != "" { require.NotNil(testRequest, "path should not be nil") - require.Equal(testCase.ExpectedRequestPath, testRequest.URL.Path) + require.Equal(tc.ExpectedRequestPath, testRequest.URL.Path) } - if testCase.ExpectedURLParams != nil { + if tc.ExpectedURLParams != nil { require.NotNil(testRequest) - for k, v := range testCase.ExpectedURLParams { + for k, v := range tc.ExpectedURLParams { value := testRequest.URL.Query().Get(k) require.Equal(v, value, fmt.Sprintf("%s not equal", k)) } } - if testCase.ExpectedPostParams != nil { + if tc.ExpectedPostParams != nil { require.NotNil(testRequest, "post body should not be nil") - for k, v := range testCase.ExpectedPostParams { + for k, v := range tc.ExpectedPostParams { value := testRequest.PostFormValue(k) require.Equal(v, value) } } - if testCase.ExpectedRequestBody != "" { + if tc.ExpectedRequestBody != "" { require.NotNil(testRequest, "request body should not be nil") value, _ := ioutil.ReadAll(testRequest.Body) - require.Equal(testCase.ExpectedRequestBody, strings.Trim(string(value), "\n")) + require.Equal(tc.ExpectedRequestBody, strings.Trim(string(value), "\n")) } - if (len(testCase.MockResponses)) != 0 { - require.Equal(mockRRCount, len(testCase.MockResponses)) + if (len(tc.MockResponses)) != 0 { + require.Equal(mockRRCount, len(tc.MockResponses)) } - if testCase.ExpectedHeaders != nil { + if tc.ExpectedHeaders != nil { require.NotNil(testRequest, "headers should not be nil") - for k, v := range testCase.ExpectedHeaders { + for k, v := range tc.ExpectedHeaders { value := testRequest.Header.Get(k) require.Equal(v, value) } } - if testCase.ExpectedExternalID != "" { - require.Equal(testCase.ExpectedExternalID, status.ExternalID()) + if tc.ExpectedExternalID != "" { + require.Equal(tc.ExpectedExternalID, status.ExternalID()) } - if testCase.ExpectedStatus != "" { + if tc.ExpectedStatus != "" { require.NotNil(status, "status should not be nil") - require.Equal(testCase.ExpectedStatus, string(status.Status())) + require.Equal(tc.ExpectedStatus, string(status.Status())) } - if testCase.ExpectedStopEvent { + if tc.ExpectedStopEvent { evt, err := mb.GetLastChannelEvent() require.NoError(err) require.Equal(courier.StopContact, evt.EventType()) } - if testCase.ExpectedContactURNs != nil { + if tc.ExpectedContactURNs != nil { var contactUUID courier.ContactUUID - for urn, shouldBePresent := range testCase.ExpectedContactURNs { + for urn, shouldBePresent := range tc.ExpectedContactURNs { contact, _ := mb.GetContact(ctx, channel, urns.URN(urn), "", "") if contactUUID == courier.NilContactUUID && shouldBePresent { contactUUID = contact.UUID() @@ -350,10 +347,10 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour } } - if testCase.ExpectedNewURN != "" { + if tc.ExpectedNewURN != "" { old, new := status.UpdatedURN() - require.Equal(urns.URN(testCase.MsgURN), old) - require.Equal(urns.URN(testCase.ExpectedNewURN), new) + require.Equal(urns.URN(tc.MsgURN), old) + require.Equal(urns.URN(tc.ExpectedNewURN), new) } }) } @@ -370,14 +367,14 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri } handler.Initialize(s) - for _, testCase := range testCases { - t.Run(testCase.Label, func(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.Label, func(t *testing.T) { require := require.New(t) mb.ClearQueueMsgs() mb.ClearSeenExternalIDs() - testHandlerRequest(t, s, testCase.URL, testCase.Headers, testCase.Data, testCase.MultipartFormFields, testCase.Status, &testCase.Response, testCase.PrepRequest) + testHandlerRequest(t, s, tc.URL, tc.Headers, tc.Data, tc.MultipartFormFields, tc.ExpectedStatus, &tc.ExpectedResponse, tc.PrepRequest) // pop our message off and test against it contactName := mb.GetLastContactName() @@ -385,68 +382,65 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri event, _ := mb.GetLastChannelEvent() status, _ := mb.GetLastMsgStatus() - if testCase.Status == 200 { - if testCase.Name != nil { - require.Equal(*testCase.Name, contactName) + if tc.ExpectedStatus == 200 { + if tc.ExpectedContactName != nil { + require.Equal(*tc.ExpectedContactName, contactName) } - if testCase.Text != nil { + if tc.ExpectedMsgText != nil { require.NotNil(msg) require.Equal(mb.LenQueuedMsgs(), 1) - require.Equal(*testCase.Text, msg.Text()) + require.Equal(*tc.ExpectedMsgText, msg.Text()) } - if testCase.ChannelEvent != nil { - require.Equal(*testCase.ChannelEvent, string(event.EventType())) + if tc.ChannelEvent != nil { + require.Equal(*tc.ChannelEvent, string(event.EventType())) } - if testCase.ChannelEventExtra != nil { - require.Equal(testCase.ChannelEventExtra, event.Extra()) + if tc.ChannelEventExtra != nil { + require.Equal(tc.ChannelEventExtra, event.Extra()) } - if testCase.URN != nil { + if tc.ExpectedURN != nil { if msg != nil { - require.Equal(*testCase.URN, string(msg.URN())) + require.Equal(*tc.ExpectedURN, string(msg.URN())) } else if event != nil { - require.Equal(*testCase.URN, string(event.URN())) + require.Equal(*tc.ExpectedURN, string(event.URN())) } else { - require.Equal(*testCase.URN, "") + require.Equal(*tc.ExpectedURN, "") } } - if testCase.URNAuth != nil { + if tc.ExpectedURNAuth != nil { if msg != nil { - require.Equal(*testCase.URNAuth, msg.URNAuth()) + require.Equal(*tc.ExpectedURNAuth, msg.URNAuth()) } } - if testCase.ExternalID != nil { + if tc.ExpectedExternalID != nil { if msg != nil { - require.Equal(*testCase.ExternalID, msg.ExternalID()) + require.Equal(*tc.ExpectedExternalID, msg.ExternalID()) } else if status != nil { - require.Equal(*testCase.ExternalID, status.ExternalID()) + require.Equal(*tc.ExpectedExternalID, status.ExternalID()) } else { - require.Equal(*testCase.ExternalID, "") + require.Equal(*tc.ExpectedExternalID, "") } } - if testCase.MsgStatus != nil { + if tc.ExpectedMsgStatus != nil { require.NotNil(status) - require.Equal(*testCase.MsgStatus, string(status.Status())) + require.Equal(*tc.ExpectedMsgStatus, string(status.Status())) } - if testCase.ID != 0 { + if tc.ExpectedMsgID != 0 { if status != nil { - require.Equal(testCase.ID, int64(status.ID())) + require.Equal(tc.ExpectedMsgID, int64(status.ID())) } else { - require.Equal(testCase.ID, -1) + require.Equal(tc.ExpectedMsgID, -1) } } - if testCase.Attachment != nil { - require.Equal([]string{*testCase.Attachment}, msg.Attachments()) - } - if len(testCase.Attachments) > 0 { - require.Equal(testCase.Attachments, msg.Attachments()) + if len(tc.ExpectedAttachments) > 0 { + require.Equal(tc.ExpectedAttachments, msg.Attachments()) } - if testCase.Date != nil { + if tc.ExpectedDate != nil { if msg != nil { - require.Equal((*testCase.Date).Local(), (*msg.ReceivedOn()).Local()) + require.Equal((*tc.ExpectedDate).Local(), (*msg.ReceivedOn()).Local()) } else if event != nil { - require.Equal(*testCase.Date, event.OccurredOn()) + require.Equal(*tc.ExpectedDate, event.OccurredOn()) } else { - require.Equal(*testCase.Date, nil) + require.Equal(*tc.ExpectedDate, nil) } } } @@ -488,7 +482,7 @@ func RunChannelBenchmarks(b *testing.B, channels []courier.Channel, handler cour b.Run(testCase.Label, func(b *testing.B) { for i := 0; i < b.N; i++ { - testHandlerRequest(b, s, testCase.URL, testCase.Headers, testCase.Data, testCase.MultipartFormFields, testCase.Status, nil, testCase.PrepRequest) + testHandlerRequest(b, s, testCase.URL, testCase.Headers, testCase.Data, testCase.MultipartFormFields, testCase.ExpectedStatus, nil, testCase.PrepRequest) } }) } diff --git a/handlers/thinq/thinq_test.go b/handlers/thinq/thinq_test.go index 5595076f3..420ef516f 100644 --- a/handlers/thinq/thinq_test.go +++ b/handlers/thinq/thinq_test.go @@ -26,18 +26,18 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: receiveValid, Status: 200, Response: "Accepted", - Text: Sp("hello world"), URN: Sp("tel:+12065551234")}, - {Label: "Receive No Params", URL: receiveURL, Data: " ", Status: 400, Response: `'From' failed on the 'required'`}, - {Label: "Receive Media", URL: receiveURL, Data: receiveMedia, Status: 200, Response: "Accepted", - URN: Sp("tel:+12065551234"), Attachments: []string{"http://foo.bar/foo.png"}}, + {Label: "Receive Valid", URL: receiveURL, Data: receiveValid, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+12065551234")}, + {Label: "Receive No Params", URL: receiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: `'From' failed on the 'required'`}, + {Label: "Receive Media", URL: receiveURL, Data: receiveMedia, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedURN: Sp("tel:+12065551234"), ExpectedAttachments: []string{"http://foo.bar/foo.png"}}, - {Label: "Status Valid", URL: statusURL, Data: statusValid, Status: 200, - ExternalID: Sp("1234"), Response: `"status":"D"`}, - {Label: "Status Invalid", URL: statusURL, Data: statusInvalid, Status: 400, - ExternalID: Sp("1234"), Response: `"unknown status: 'UN'"`}, - {Label: "Status Missing GUID", URL: statusURL, Data: missingGUID, Status: 400, - ExternalID: Sp("1234"), Response: `'GUID' failed on the 'required' tag`}, + {Label: "Status Valid", URL: statusURL, Data: statusValid, ExpectedStatus: 200, + ExpectedExternalID: Sp("1234"), ExpectedResponse: `"status":"D"`}, + {Label: "Status Invalid", URL: statusURL, Data: statusInvalid, ExpectedStatus: 400, + ExpectedExternalID: Sp("1234"), ExpectedResponse: `"unknown status: 'UN'"`}, + {Label: "Status Missing GUID", URL: statusURL, Data: missingGUID, ExpectedStatus: 400, + ExpectedExternalID: Sp("1234"), ExpectedResponse: `'GUID' failed on the 'required' tag`}, } func TestHandler(t *testing.T) { diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index 373712ff9..051bbac33 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -76,160 +76,160 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: receiveValid, Status: 200, Response: "", - Text: Sp("Msg"), URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Receive Valid", URL: receiveURL, Data: receiveValid, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, - {Label: "Receive Button Ignored", URL: receiveURL, Data: receiveButtonIgnored, Status: 200, Response: "", - Text: Sp("Msg"), URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Receive Button Ignored", URL: receiveURL, Data: receiveButtonIgnored, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, - {Label: "Receive Invalid Signature", URL: receiveURL, Data: receiveValid, Status: 400, Response: "invalid request signature", + {Label: "Receive Invalid Signature", URL: receiveURL, Data: receiveValid, ExpectedStatus: 400, ExpectedResponse: "invalid request signature", PrepRequest: addInvalidSignature}, - {Label: "Receive Missing Signature", URL: receiveURL, Data: receiveValid, Status: 400, Response: "missing request signature"}, - {Label: "Receive No Params", URL: receiveURL, Data: " ", Status: 400, Response: "field 'messagesid' required", + {Label: "Receive Missing Signature", URL: receiveURL, Data: receiveValid, ExpectedStatus: 400, ExpectedResponse: "missing request signature"}, + {Label: "Receive No Params", URL: receiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: "field 'messagesid' required", PrepRequest: addValidSignature}, - {Label: "Receive Media", URL: receiveURL, Data: receiveMedia, Status: 200, Response: "", - URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), Attachments: []string{"cat.jpg", "dog.jpg"}, + {Label: "Receive Media", URL: receiveURL, Data: receiveMedia, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Media With Msg", URL: receiveURL, Data: receiveMediaWithMsg, Status: 200, Response: "", - Text: Sp("Msg"), URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), Attachments: []string{"cat.jpg", "dog.jpg"}, + {Label: "Receive Media With Msg", URL: receiveURL, Data: receiveMediaWithMsg, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Base64", URL: receiveURL, Data: receiveBase64, Status: 200, Response: "", - Text: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Receive Base64", URL: receiveURL, Data: receiveBase64, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, - {Label: "Status Stop contact", URL: statusURL, Data: statusStop, Status: 200, Response: `"status":"F"`, + {Label: "Status Stop contact", URL: statusURL, Data: statusStop, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, PrepRequest: addValidSignature}, - {Label: "Status No Params", URL: statusURL, Data: " ", Status: 200, Response: "no msg status, ignoring", + {Label: "Status No Params", URL: statusURL, Data: " ", ExpectedStatus: 200, ExpectedResponse: "no msg status, ignoring", PrepRequest: addValidSignature}, - {Label: "Status Invalid Status", URL: statusURL, Data: statusInvalid, Status: 400, Response: "unknown status 'huh'", + {Label: "Status Invalid Status", URL: statusURL, Data: statusInvalid, ExpectedStatus: 400, ExpectedResponse: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: statusURL, Data: statusValid, Status: 200, Response: `"status":"D"`, ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status Valid", URL: statusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, - {Label: "Status Read", URL: statusURL, Data: statusRead, Status: 200, Response: `"status":"D"`, ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status Read", URL: statusURL, Data: statusRead, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, - {Label: "Status ID Valid", URL: statusIDURL, Data: statusValid, Status: 200, Response: `"status":"D"`, ID: 12345, + {Label: "Status ID Valid", URL: statusIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: statusInvalidIDURL, Data: statusValid, Status: 200, Response: `"status":"D"`, ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status ID Invalid", URL: statusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, } var tmsTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: tmsReceiveURL, Data: receiveValid, Status: 200, Response: "", - Text: Sp("Msg"), URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Receive Valid", URL: tmsReceiveURL, Data: receiveValid, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, - {Label: "Receive TMS extra", URL: tmsReceiveURL, Data: tmsReceiveExtra, Status: 200, Response: "", - Text: Sp("John Cruz"), URN: Sp("tel:+14133881111"), ExternalID: Sp("SMbbf29aeb9d380ce2a1c0ae4635ff9dab"), + {Label: "Receive TMS extra", URL: tmsReceiveURL, Data: tmsReceiveExtra, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("John Cruz"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMbbf29aeb9d380ce2a1c0ae4635ff9dab"), PrepRequest: addValidSignature}, - {Label: "Receive Invalid Signature", URL: tmsReceiveURL, Data: receiveValid, Status: 400, Response: "invalid request signature", + {Label: "Receive Invalid Signature", URL: tmsReceiveURL, Data: receiveValid, ExpectedStatus: 400, ExpectedResponse: "invalid request signature", PrepRequest: addInvalidSignature}, - {Label: "Receive Missing Signature", URL: tmsReceiveURL, Data: receiveValid, Status: 400, Response: "missing request signature"}, - {Label: "Receive No Params", URL: tmsReceiveURL, Data: " ", Status: 400, Response: "field 'messagesid' required", + {Label: "Receive Missing Signature", URL: tmsReceiveURL, Data: receiveValid, ExpectedStatus: 400, ExpectedResponse: "missing request signature"}, + {Label: "Receive No Params", URL: tmsReceiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: "field 'messagesid' required", PrepRequest: addValidSignature}, - {Label: "Receive Media", URL: tmsReceiveURL, Data: receiveMedia, Status: 200, Response: "", - URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), Attachments: []string{"cat.jpg", "dog.jpg"}, + {Label: "Receive Media", URL: tmsReceiveURL, Data: receiveMedia, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Media With Msg", URL: tmsReceiveURL, Data: receiveMediaWithMsg, Status: 200, Response: "", - Text: Sp("Msg"), URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), Attachments: []string{"cat.jpg", "dog.jpg"}, + {Label: "Receive Media With Msg", URL: tmsReceiveURL, Data: receiveMediaWithMsg, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Base64", URL: tmsReceiveURL, Data: receiveBase64, Status: 200, Response: "", - Text: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Receive Base64", URL: tmsReceiveURL, Data: receiveBase64, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, - {Label: "Status Stop contact", URL: tmsStatusURL, Data: statusStop, Status: 200, Response: `"status":"F"`, + {Label: "Status Stop contact", URL: tmsStatusURL, Data: statusStop, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, PrepRequest: addValidSignature}, - {Label: "Status TMS extra", URL: tmsStatusURL, Data: tmsStatusExtra, Status: 200, Response: `"status":"S"`, - ExternalID: Sp("SM0b6e2697aae04182a9f5b5c7a8994c7f"), PrepRequest: addValidSignature}, - {Label: "Status No Params", URL: tmsStatusURL, Data: " ", Status: 200, Response: "no msg status, ignoring", + {Label: "Status TMS extra", URL: tmsStatusURL, Data: tmsStatusExtra, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`, + ExpectedExternalID: Sp("SM0b6e2697aae04182a9f5b5c7a8994c7f"), PrepRequest: addValidSignature}, + {Label: "Status No Params", URL: tmsStatusURL, Data: " ", ExpectedStatus: 200, ExpectedResponse: "no msg status, ignoring", PrepRequest: addValidSignature}, - {Label: "Status Invalid Status", URL: tmsStatusURL, Data: statusInvalid, Status: 400, Response: "unknown status 'huh'", + {Label: "Status Invalid Status", URL: tmsStatusURL, Data: statusInvalid, ExpectedStatus: 400, ExpectedResponse: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: tmsStatusURL, Data: statusValid, Status: 200, Response: `"status":"D"`, ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status Valid", URL: tmsStatusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, - {Label: "Status ID Valid", URL: tmsStatusIDURL, Data: statusValid, Status: 200, Response: `"status":"D"`, ID: 12345, + {Label: "Status ID Valid", URL: tmsStatusIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: tmsStatusInvalidIDURL, Data: statusValid, Status: 200, Response: `"status":"D"`, ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status ID Invalid", URL: tmsStatusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, } var twTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: twReceiveURL, Data: receiveValid, Status: 200, Response: "", - Text: Sp("Msg"), URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Receive Valid", URL: twReceiveURL, Data: receiveValid, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, {Label: "Receive Forwarded Valid", URL: twReceiveURL, Data: receiveValid, - Headers: map[string]string{forwardedPathHeader: "/handlers/twilio/receive/8eb23e93-5ecb-45ba-b726-3b064e0c56ab"}, - Status: 200, Response: "", - Text: Sp("Msg"), URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + Headers: map[string]string{forwardedPathHeader: "/handlers/twilio/receive/8eb23e93-5ecb-45ba-b726-3b064e0c56ab"}, + ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addForwardSignature}, - {Label: "Receive Invalid Signature", URL: twReceiveURL, Data: receiveValid, Status: 400, Response: "invalid request signature", + {Label: "Receive Invalid Signature", URL: twReceiveURL, Data: receiveValid, ExpectedStatus: 400, ExpectedResponse: "invalid request signature", PrepRequest: addInvalidSignature}, - {Label: "Receive Missing Signature", URL: twReceiveURL, Data: receiveValid, Status: 400, Response: "missing request signature"}, - {Label: "Receive No Params", URL: twReceiveURL, Data: " ", Status: 400, Response: "field 'messagesid' required", + {Label: "Receive Missing Signature", URL: twReceiveURL, Data: receiveValid, ExpectedStatus: 400, ExpectedResponse: "missing request signature"}, + {Label: "Receive No Params", URL: twReceiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: "field 'messagesid' required", PrepRequest: addValidSignature}, - {Label: "Receive Media", URL: twReceiveURL, Data: receiveMedia, Status: 200, Response: "", - URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), Attachments: []string{"cat.jpg", "dog.jpg"}, + {Label: "Receive Media", URL: twReceiveURL, Data: receiveMedia, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Media With Msg", URL: twReceiveURL, Data: receiveMediaWithMsg, Status: 200, Response: "", - Text: Sp("Msg"), URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), Attachments: []string{"cat.jpg", "dog.jpg"}, + {Label: "Receive Media With Msg", URL: twReceiveURL, Data: receiveMediaWithMsg, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Base64", URL: twReceiveURL, Data: receiveBase64, Status: 200, Response: "", - Text: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Receive Base64", URL: twReceiveURL, Data: receiveBase64, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, - {Label: "Status Stop contact", URL: twStatusURL, Data: statusStop, Status: 200, Response: `"status":"F"`, + {Label: "Status Stop contact", URL: twStatusURL, Data: statusStop, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, PrepRequest: addValidSignature}, - {Label: "Status No Params", URL: twStatusURL, Data: " ", Status: 200, Response: "no msg status, ignoring", + {Label: "Status No Params", URL: twStatusURL, Data: " ", ExpectedStatus: 200, ExpectedResponse: "no msg status, ignoring", PrepRequest: addValidSignature}, - {Label: "Status Invalid Status", URL: twStatusURL, Data: statusInvalid, Status: 400, Response: "unknown status 'huh'", + {Label: "Status Invalid Status", URL: twStatusURL, Data: statusInvalid, ExpectedStatus: 400, ExpectedResponse: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: twStatusURL, Data: statusValid, Status: 200, Response: `"status":"D"`, ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status Valid", URL: twStatusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, - {Label: "Status ID Valid", URL: twStatusIDURL, Data: statusValid, Status: 200, Response: `"status":"D"`, ID: 12345, + {Label: "Status ID Valid", URL: twStatusIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: twStatusInvalidIDURL, Data: statusValid, Status: 200, Response: `"status":"D"`, ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status ID Invalid", URL: twStatusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, } var swTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: swReceiveURL, Data: receiveValid, Status: 200, Response: "", - Text: Sp("Msg"), URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b")}, - {Label: "Receive No Params", URL: swReceiveURL, Data: " ", Status: 400, Response: "field 'messagesid' required"}, - {Label: "Receive Media", URL: swReceiveURL, Data: receiveMedia, Status: 200, Response: "", - URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), Attachments: []string{"cat.jpg", "dog.jpg"}}, - {Label: "Receive Media With Msg", URL: swReceiveURL, Data: receiveMediaWithMsg, Status: 200, Response: "", - Text: Sp("Msg"), URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), Attachments: []string{"cat.jpg", "dog.jpg"}}, - {Label: "Receive Base64", URL: swReceiveURL, Data: receiveBase64, Status: 200, Response: "", - Text: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), URN: Sp("tel:+14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b")}, - {Label: "Status Stop contact", URL: swStatusURL, Data: statusStop, Status: 200, Response: `"status":"F"`, - PrepRequest: addValidSignature}, - {Label: "Status No Params", URL: swStatusURL, Data: " ", Status: 200, Response: "no msg status, ignoring"}, - {Label: "Status Invalid Status", URL: swStatusURL, Data: statusInvalid, Status: 400, Response: "unknown status 'huh'"}, - {Label: "Status Valid", URL: swStatusURL, Data: statusValid, Status: 200, Response: `"status":"D"`, ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b")}, - {Label: "Status ID Valid", URL: swStatusIDURL, Data: statusValid, Status: 200, Response: `"status":"D"`, ID: 12345}, - {Label: "Status ID Invalid", URL: swStatusInvalidIDURL, Data: statusValid, Status: 200, Response: `"status":"D"`, ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b")}, + {Label: "Receive Valid", URL: swReceiveURL, Data: receiveValid, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b")}, + {Label: "Receive No Params", URL: swReceiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: "field 'messagesid' required"}, + {Label: "Receive Media", URL: swReceiveURL, Data: receiveMedia, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}}, + {Label: "Receive Media With Msg", URL: swReceiveURL, Data: receiveMediaWithMsg, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}}, + {Label: "Receive Base64", URL: swReceiveURL, Data: receiveBase64, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b")}, + {Label: "Status Stop contact", URL: swStatusURL, Data: statusStop, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, + PrepRequest: addValidSignature}, + {Label: "Status No Params", URL: swStatusURL, Data: " ", ExpectedStatus: 200, ExpectedResponse: "no msg status, ignoring"}, + {Label: "Status Invalid Status", URL: swStatusURL, Data: statusInvalid, ExpectedStatus: 400, ExpectedResponse: "unknown status 'huh'"}, + {Label: "Status Valid", URL: swStatusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b")}, + {Label: "Status ID Valid", URL: swStatusIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedMsgID: 12345}, + {Label: "Status ID Invalid", URL: swStatusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b")}, } var waTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: waReceiveValid, Status: 200, Response: "", - Text: Sp("Msg"), URN: Sp("whatsapp:14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Receive Valid", URL: receiveURL, Data: waReceiveValid, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("whatsapp:14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, } var twaTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: twaReceiveURL, Data: waReceiveValid, Status: 200, Response: "", - Text: Sp("Msg"), URN: Sp("whatsapp:14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Receive Valid", URL: twaReceiveURL, Data: waReceiveValid, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("whatsapp:14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, - {Label: "Receive Valid", URL: twaReceiveURL, Data: waReceiveButtonValid, Status: 200, Response: "", - Text: Sp("Confirm"), URN: Sp("whatsapp:14133881111"), ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Receive Valid", URL: twaReceiveURL, Data: waReceiveButtonValid, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Confirm"), ExpectedURN: Sp("whatsapp:14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, - {Label: "Receive Prefixless URN", URL: twaReceiveURL, Data: waReceivePrefixlessURN, Status: 200, Response: "", - Text: Sp("Msg"), URN: Sp("whatsapp:14133881111"), ExternalID: Sp("SM681a1f26d9ec591431ce406e8f399525"), + {Label: "Receive Prefixless URN", URL: twaReceiveURL, Data: waReceivePrefixlessURN, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("whatsapp:14133881111"), ExpectedExternalID: Sp("SM681a1f26d9ec591431ce406e8f399525"), PrepRequest: addValidSignature}, - {Label: "Status No Params", URL: twaStatusURL, Data: " ", Status: 200, Response: "no msg status, ignoring", + {Label: "Status No Params", URL: twaStatusURL, Data: " ", ExpectedStatus: 200, ExpectedResponse: "no msg status, ignoring", PrepRequest: addValidSignature}, - {Label: "Status Invalid Status", URL: twaStatusURL, Data: statusInvalid, Status: 400, Response: "unknown status 'huh'", + {Label: "Status Invalid Status", URL: twaStatusURL, Data: statusInvalid, ExpectedStatus: 400, ExpectedResponse: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: twaStatusURL, Data: statusValid, Status: 200, Response: `"status":"D"`, ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status Valid", URL: twaStatusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, - {Label: "Status ID Valid", URL: twaStatusIDURL, Data: statusValid, Status: 200, Response: `"status":"D"`, ID: 12345, + {Label: "Status ID Valid", URL: twaStatusIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: twaStatusInvalidIDURL, Data: statusValid, Status: 200, Response: `"status":"D"`, ExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status ID Invalid", URL: twaStatusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), PrepRequest: addValidSignature}, } diff --git a/handlers/twitter/twitter_test.go b/handlers/twitter/twitter_test.go index 676c0d34b..c093a6a43 100644 --- a/handlers/twitter/twitter_test.go +++ b/handlers/twitter/twitter_test.go @@ -166,17 +166,17 @@ var attachment = `{ var notJSON = `blargh` var testCases = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: helloMsg, Status: 200, Response: "Accepted", - Name: Sp("Nicolas Pottier"), URN: Sp("twitterid:272953809#nicpottier"), - Text: Sp("Hello World & good wishes."), ExternalID: Sp("958501034212564996"), Date: Tp(time.Date(2018, 1, 31, 0, 43, 49, 301000000, time.UTC))}, - {Label: "Receive Attachment", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: attachment, Status: 200, Response: "Accepted", - Text: Sp("Hello"), Attachments: []string{"https://image.foo.com/image.jpg"}, URN: Sp("twitterid:272953809#nicpottier"), ExternalID: Sp("958501034212564996"), Date: Tp(time.Date(2018, 1, 31, 0, 43, 49, 301000000, time.UTC))}, - {Label: "Not JSON", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: notJSON, Status: 400, Response: "Error"}, - {Label: "Invalid Twitter handle", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidTwitterHandle, Status: 400, Response: "invalid twitter handle"}, - {Label: "Invalid Twitter ID", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidTwitterID, Status: 400, Response: "invalid twitter id"}, + {Label: "Receive Message", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedContactName: Sp("Nicolas Pottier"), ExpectedURN: Sp("twitterid:272953809#nicpottier"), + ExpectedMsgText: Sp("Hello World & good wishes."), ExpectedExternalID: Sp("958501034212564996"), ExpectedDate: Tp(time.Date(2018, 1, 31, 0, 43, 49, 301000000, time.UTC))}, + {Label: "Receive Attachment", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: attachment, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Hello"), ExpectedAttachments: []string{"https://image.foo.com/image.jpg"}, ExpectedURN: Sp("twitterid:272953809#nicpottier"), ExpectedExternalID: Sp("958501034212564996"), ExpectedDate: Tp(time.Date(2018, 1, 31, 0, 43, 49, 301000000, time.UTC))}, + {Label: "Not JSON", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "Error"}, + {Label: "Invalid Twitter handle", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidTwitterHandle, ExpectedStatus: 400, ExpectedResponse: "invalid twitter handle"}, + {Label: "Invalid Twitter ID", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidTwitterID, ExpectedStatus: 400, ExpectedResponse: "invalid twitter id"}, - {Label: "Webhook Verification", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?crc_token=test+token", Status: 200, Response: "sha256=O5hJl2njQRIa4vsumZ+3oom9ECR5m3aQLRZkPoYelp0="}, - {Label: "Webhook Verification Error", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Status: 400, Response: "missing required 'crc_token'"}, + {Label: "Webhook Verification", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?crc_token=test+token", ExpectedStatus: 200, ExpectedResponse: "sha256=O5hJl2njQRIa4vsumZ+3oom9ECR5m3aQLRZkPoYelp0="}, + {Label: "Webhook Verification Error", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", ExpectedStatus: 400, ExpectedResponse: "missing required 'crc_token'"}, } func TestHandler(t *testing.T) { diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index f7f2b55f9..1fd9eb71a 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -465,51 +465,51 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validMsg, Status: 200, Response: "Accepted", - Text: Sp("incoming msg"), URN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExternalID: Sp("4987381189870374000"), + {Label: "Receive Valid", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("incoming msg"), ExpectedURN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExpectedExternalID: Sp("4987381189870374000"), PrepRequest: addValidSignature}, - {Label: "Receive invalid signature", URL: receiveURL, Data: validMsg, Status: 400, Response: "invalid request signature", + {Label: "Receive invalid signature", URL: receiveURL, Data: validMsg, ExpectedStatus: 400, ExpectedResponse: "invalid request signature", PrepRequest: addInvalidSignature}, - {Label: "Receive invalid JSON", URL: receiveURL, Data: invalidJSON, Status: 400, Response: "unable to parse request JSON", + {Label: "Receive invalid JSON", URL: receiveURL, Data: invalidJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON", PrepRequest: addValidSignature}, - {Label: "Receive invalid URN", URL: receiveURL, Data: invalidURNMsg, Status: 400, Response: "invalid viber id", + {Label: "Receive invalid URN", URL: receiveURL, Data: invalidURNMsg, ExpectedStatus: 400, ExpectedResponse: "invalid viber id", PrepRequest: addValidSignature}, - {Label: "Receive invalid Message Type", URL: receiveURL, Data: receiveInvalidMessageType, Status: 400, Response: "unknown message type", + {Label: "Receive invalid Message Type", URL: receiveURL, Data: receiveInvalidMessageType, ExpectedStatus: 400, ExpectedResponse: "unknown message type", PrepRequest: addValidSignature}, - {Label: "Webhook validation", URL: receiveURL, Data: webhookCheck, Status: 200, Response: "webhook valid", PrepRequest: addValidSignature}, - {Label: "Failed Status Report", URL: receiveURL, Data: failedStatusReport, Status: 200, Response: `"status":"F"`, PrepRequest: addValidSignature}, - {Label: "Delivered Status Report", URL: receiveURL, Data: deliveredStatusReport, Status: 200, Response: `Ignored`, PrepRequest: addValidSignature}, - {Label: "Subcribe", URL: receiveURL, Data: validSubscribed, Status: 200, Response: "Accepted", PrepRequest: addValidSignature}, - {Label: "Subcribe Invalid URN", URL: receiveURL, Data: invalidURNSubscribed, Status: 400, Response: "invalid viber id", PrepRequest: addValidSignature}, - {Label: "Unsubcribe", URL: receiveURL, Data: validUnsubscribed, Status: 200, Response: "Accepted", ChannelEvent: Sp(string(courier.StopContact)), PrepRequest: addValidSignature}, - {Label: "Unsubcribe Invalid URN", URL: receiveURL, Data: invalidURNUnsubscribed, Status: 400, Response: "invalid viber id", PrepRequest: addValidSignature}, - {Label: "Conversation Started", URL: receiveURL, Data: validConversationStarted, Status: 200, Response: "ignored conversation start", PrepRequest: addValidSignature}, - {Label: "Unexpected event", URL: receiveURL, Data: unexpectedEvent, Status: 400, - Response: "not handled, unknown event: unexpected", PrepRequest: addValidSignature}, - {Label: "Message missing text", URL: receiveURL, Data: rejectedMessage, Status: 400, Response: "missing text or media in message in request body", PrepRequest: addValidSignature}, - {Label: "Picture missing media", URL: receiveURL, Data: rejectedPicture, Status: 400, Response: "missing text or media in message in request body", PrepRequest: addValidSignature}, - {Label: "Video missing media", URL: receiveURL, Data: rejectedVideo, Status: 400, Response: "missing text or media in message in request body", PrepRequest: addValidSignature}, - - {Label: "Valid Contact receive", URL: receiveURL, Data: validReceiveContact, Status: 200, Response: "Accepted", - Text: Sp("Alex: +12067799191"), URN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExternalID: Sp("4987381189870374000"), + {Label: "Webhook validation", URL: receiveURL, Data: webhookCheck, ExpectedStatus: 200, ExpectedResponse: "webhook valid", PrepRequest: addValidSignature}, + {Label: "Failed Status Report", URL: receiveURL, Data: failedStatusReport, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, PrepRequest: addValidSignature}, + {Label: "Delivered Status Report", URL: receiveURL, Data: deliveredStatusReport, ExpectedStatus: 200, ExpectedResponse: `Ignored`, PrepRequest: addValidSignature}, + {Label: "Subcribe", URL: receiveURL, Data: validSubscribed, ExpectedStatus: 200, ExpectedResponse: "Accepted", PrepRequest: addValidSignature}, + {Label: "Subcribe Invalid URN", URL: receiveURL, Data: invalidURNSubscribed, ExpectedStatus: 400, ExpectedResponse: "invalid viber id", PrepRequest: addValidSignature}, + {Label: "Unsubcribe", URL: receiveURL, Data: validUnsubscribed, ExpectedStatus: 200, ExpectedResponse: "Accepted", ChannelEvent: Sp(string(courier.StopContact)), PrepRequest: addValidSignature}, + {Label: "Unsubcribe Invalid URN", URL: receiveURL, Data: invalidURNUnsubscribed, ExpectedStatus: 400, ExpectedResponse: "invalid viber id", PrepRequest: addValidSignature}, + {Label: "Conversation Started", URL: receiveURL, Data: validConversationStarted, ExpectedStatus: 200, ExpectedResponse: "ignored conversation start", PrepRequest: addValidSignature}, + {Label: "Unexpected event", URL: receiveURL, Data: unexpectedEvent, ExpectedStatus: 400, + ExpectedResponse: "not handled, unknown event: unexpected", PrepRequest: addValidSignature}, + {Label: "Message missing text", URL: receiveURL, Data: rejectedMessage, ExpectedStatus: 400, ExpectedResponse: "missing text or media in message in request body", PrepRequest: addValidSignature}, + {Label: "Picture missing media", URL: receiveURL, Data: rejectedPicture, ExpectedStatus: 400, ExpectedResponse: "missing text or media in message in request body", PrepRequest: addValidSignature}, + {Label: "Video missing media", URL: receiveURL, Data: rejectedVideo, ExpectedStatus: 400, ExpectedResponse: "missing text or media in message in request body", PrepRequest: addValidSignature}, + + {Label: "Valid Contact receive", URL: receiveURL, Data: validReceiveContact, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Alex: +12067799191"), ExpectedURN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExpectedExternalID: Sp("4987381189870374000"), PrepRequest: addValidSignature}, - {Label: "Valid URL receive", URL: receiveURL, Data: validReceiveURL, Status: 200, Response: "Accepted", - Text: Sp("http://foo.com/"), URN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExternalID: Sp("4987381189870374000"), + {Label: "Valid URL receive", URL: receiveURL, Data: validReceiveURL, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("http://foo.com/"), ExpectedURN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExpectedExternalID: Sp("4987381189870374000"), PrepRequest: addValidSignature}, - {Label: "Valid Location receive", URL: receiveURL, Data: validReceiveLocation, Status: 200, Response: "Accepted", - Text: Sp("incoming msg"), URN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExternalID: Sp("4987381189870374000"), - Attachment: Sp("geo:1.200000,-1.300000"), PrepRequest: addValidSignature}, - {Label: "Valid Sticker", URL: receiveURL, Data: validSticker, Status: 200, Response: "Accepted", - Text: Sp("incoming msg"), URN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExternalID: Sp("4987381189870374000"), - Attachment: Sp("https://viber.github.io/docs/img/stickers/40133.png"), PrepRequest: addValidSignature}, + {Label: "Valid Location receive", URL: receiveURL, Data: validReceiveLocation, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("incoming msg"), ExpectedURN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExpectedExternalID: Sp("4987381189870374000"), + ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, PrepRequest: addValidSignature}, + {Label: "Valid Sticker", URL: receiveURL, Data: validSticker, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("incoming msg"), ExpectedURN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExpectedExternalID: Sp("4987381189870374000"), + ExpectedAttachments: []string{"https://viber.github.io/docs/img/stickers/40133.png"}, PrepRequest: addValidSignature}, } var testWelcomeMessageCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validMsg, Status: 200, Response: "Accepted", - Text: Sp("incoming msg"), URN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExternalID: Sp("4987381189870374000"), + {Label: "Receive Valid", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("incoming msg"), ExpectedURN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExpectedExternalID: Sp("4987381189870374000"), PrepRequest: addValidSignature}, - {Label: "Conversation Started", URL: receiveURL, Data: validConversationStarted, Status: 200, Response: `{"auth_token":"Token","text":"Welcome to VP, Please subscribe here for more.","type":"text","tracking_data":"0"}`, PrepRequest: addValidSignature}, + {Label: "Conversation Started", URL: receiveURL, Data: validConversationStarted, ExpectedStatus: 200, ExpectedResponse: `{"auth_token":"Token","text":"Welcome to VP, Please subscribe here for more.","type":"text","tracking_data":"0"}`, PrepRequest: addValidSignature}, } func addValidSignature(r *http.Request) { diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index f9ea385c4..8128db894 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -230,115 +230,115 @@ const keyboardJson = `{"one_time":true,"buttons":[[{"action":{"type":"text","lab var testCases = []ChannelHandleTestCase{ { - Label: "Receive Message", - URL: receiveURL, - Data: msgHelloWorld, - Status: 200, - Response: "ok", - URN: Sp("vk:123456"), - ExternalID: Sp("1"), - Date: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), + Label: "Receive Message", + URL: receiveURL, + Data: msgHelloWorld, + ExpectedStatus: 200, + ExpectedResponse: "ok", + ExpectedURN: Sp("vk:123456"), + ExpectedExternalID: Sp("1"), + ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), }, { - Label: "Receive Empty Message", - URL: receiveURL, - Data: msgEmpty, - Status: 400, - Response: "no text or attachment", - URN: Sp("vk:123456"), - ExternalID: Sp("1"), - Date: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), + Label: "Receive Empty Message", + URL: receiveURL, + Data: msgEmpty, + ExpectedStatus: 400, + ExpectedResponse: "no text or attachment", + ExpectedURN: Sp("vk:123456"), + ExpectedExternalID: Sp("1"), + ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), }, { - Label: "Receive First Photo Attachment", - URL: receiveURL, - Data: msgFirstPhotoAttachment, - Status: 200, - Response: "ok", - URN: Sp("vk:123456"), - ExternalID: Sp("1"), - Date: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), Attachments: []string{"https://foo.bar/x-photo.jpg"}, + Label: "Receive First Photo Attachment", + URL: receiveURL, + Data: msgFirstPhotoAttachment, + ExpectedStatus: 200, + ExpectedResponse: "ok", + ExpectedURN: Sp("vk:123456"), + ExpectedExternalID: Sp("1"), + ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), ExpectedAttachments: []string{"https://foo.bar/x-photo.jpg"}, }, { - Label: "Receive First Graffiti Attachment", - URL: receiveURL, - Data: msgFirstGraffitiAttachment, - Status: 200, - Response: "ok", - URN: Sp("vk:123456"), - ExternalID: Sp("1"), - Date: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), Attachments: []string{"https://foo.bar/graffiti.png"}, + Label: "Receive First Graffiti Attachment", + URL: receiveURL, + Data: msgFirstGraffitiAttachment, + ExpectedStatus: 200, + ExpectedResponse: "ok", + ExpectedURN: Sp("vk:123456"), + ExpectedExternalID: Sp("1"), + ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), ExpectedAttachments: []string{"https://foo.bar/graffiti.png"}, }, { - Label: "Receive First Sticker Attachment", - URL: receiveURL, - Data: msgFirstStickerAttachment, - Status: 200, - Response: "ok", - URN: Sp("vk:123456"), - ExternalID: Sp("1"), - Date: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), Attachments: []string{"https://foo.bar/128x128_sticker.png"}, + Label: "Receive First Sticker Attachment", + URL: receiveURL, + Data: msgFirstStickerAttachment, + ExpectedStatus: 200, + ExpectedResponse: "ok", + ExpectedURN: Sp("vk:123456"), + ExpectedExternalID: Sp("1"), + ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), ExpectedAttachments: []string{"https://foo.bar/128x128_sticker.png"}, }, { - Label: "Receive First Audio Attachment", - URL: receiveURL, - Data: msgFirstAudioAttachment, - Status: 200, - Response: "ok", - URN: Sp("vk:123456"), - ExternalID: Sp("1"), - Date: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), Attachments: []string{"https://foo.bar/audio.mp3"}, + Label: "Receive First Audio Attachment", + URL: receiveURL, + Data: msgFirstAudioAttachment, + ExpectedStatus: 200, + ExpectedResponse: "ok", + ExpectedURN: Sp("vk:123456"), + ExpectedExternalID: Sp("1"), + ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), ExpectedAttachments: []string{"https://foo.bar/audio.mp3"}, }, { - Label: "Receive First Audio Attachment", - URL: receiveURL, - Data: msgFirstDocAttachment, - Status: 200, - Response: "ok", - URN: Sp("vk:123456"), - ExternalID: Sp("1"), - Date: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), Attachments: []string{"https://foo.bar/doc.pdf"}, + Label: "Receive First Audio Attachment", + URL: receiveURL, + Data: msgFirstDocAttachment, + ExpectedStatus: 200, + ExpectedResponse: "ok", + ExpectedURN: Sp("vk:123456"), + ExpectedExternalID: Sp("1"), + ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), ExpectedAttachments: []string{"https://foo.bar/doc.pdf"}, }, { - Label: "Receive Message Keyboard", - URL: receiveURL, - Data: msgKeyboard, - Status: 200, - Response: "ok", - URN: Sp("vk:123456"), - ExternalID: Sp("1"), - Date: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), + Label: "Receive Message Keyboard", + URL: receiveURL, + Data: msgKeyboard, + ExpectedStatus: 200, + ExpectedResponse: "ok", + ExpectedURN: Sp("vk:123456"), + ExpectedExternalID: Sp("1"), + ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), }, { - Label: "Receive Geolocation Attachment", - URL: receiveURL, - Data: msgGeolocationOnly, - Status: 200, - Response: "ok", - URN: Sp("vk:123456"), - ExternalID: Sp("1"), - Date: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), Attachments: []string{"geo:-9.652278,-35.701095"}, + Label: "Receive Geolocation Attachment", + URL: receiveURL, + Data: msgGeolocationOnly, + ExpectedStatus: 200, + ExpectedResponse: "ok", + ExpectedURN: Sp("vk:123456"), + ExpectedExternalID: Sp("1"), + ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), ExpectedAttachments: []string{"geo:-9.652278,-35.701095"}, }, { - Label: "Validate secret", - URL: receiveURL, - Data: eventWithSecret, - Status: 200, - Response: "no message or server verification event", + Label: "Validate secret", + URL: receiveURL, + Data: eventWithSecret, + ExpectedStatus: 200, + ExpectedResponse: "no message or server verification event", }, { - Label: "Invalidate secret", - URL: receiveURL, - Data: eventWithoutSecret, - Status: 400, - Response: "wrong secret key", + Label: "Invalidate secret", + URL: receiveURL, + Data: eventWithoutSecret, + ExpectedStatus: 400, + ExpectedResponse: "wrong secret key", }, { - Label: "Verify server", - URL: receiveURL, - Data: eventServerVerification, - Status: 200, - Response: "a1b2c3", + Label: "Verify server", + URL: receiveURL, + Data: eventServerVerification, + ExpectedStatus: 200, + ExpectedResponse: "a1b2c3", }, } diff --git a/handlers/wavy/wavy_test.go b/handlers/wavy/wavy_test.go index 0d061dcd8..fbd0e8c6b 100644 --- a/handlers/wavy/wavy_test.go +++ b/handlers/wavy/wavy_test.go @@ -79,20 +79,20 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: receiveURL, Data: validReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Eu quero pizza"), URN: Sp("tel:+5516981562820"), ExternalID: Sp("external_id"), Date: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, - {Label: "Invalid JSON receive", URL: receiveURL, Data: notJSON, Status: 400, Response: "unable to parse request JSON"}, - {Label: "Missing Keys receive", URL: receiveURL, Data: missingRequiredKeys, Status: 400, Response: "validation for 'ID' failed on the 'required'"}, - - {Label: "Sent Status Valid", URL: sentStatusURL, Data: validSentStatus, Status: 200, Response: "Status Update Accepted", MsgStatus: Sp(courier.MsgSent)}, - {Label: "Unknown Sent Status Valid", URL: sentStatusURL, Data: unknownSentStatus, Status: 400, Response: "unknown sent status code", MsgStatus: Sp(courier.MsgWired)}, - {Label: "Invalid JSON sent Status", URL: sentStatusURL, Data: notJSON, Status: 400, Response: "unable to parse request JSON"}, - {Label: "Missing Keys sent Status", URL: sentStatusURL, Data: missingRequiredKeys, Status: 400, Response: "validation for 'CollerationID' failed on the 'required'"}, - - {Label: "Delivered Status Valid", URL: deliveredStatusURL, Data: validDeliveredStatus, Status: 200, Response: "Status Update Accepted", MsgStatus: Sp(courier.MsgDelivered)}, - {Label: "Unknown Delivered Status Valid", URL: deliveredStatusURL, Data: unknownDeliveredStatus, Status: 400, Response: "unknown delivered status code", MsgStatus: Sp(courier.MsgSent)}, - {Label: "Invalid JSON delivered Statu", URL: deliveredStatusURL, Data: notJSON, Status: 400, Response: "unable to parse request JSON"}, - {Label: "Missing Keys sent Status", URL: deliveredStatusURL, Data: missingRequiredKeys, Status: 400, Response: "validation for 'CollerationID' failed on the 'required'"}, + {Label: "Receive Message", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Eu quero pizza"), ExpectedURN: Sp("tel:+5516981562820"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, + {Label: "Invalid JSON receive", URL: receiveURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, + {Label: "Missing Keys receive", URL: receiveURL, Data: missingRequiredKeys, ExpectedStatus: 400, ExpectedResponse: "validation for 'ID' failed on the 'required'"}, + + {Label: "Sent Status Valid", URL: sentStatusURL, Data: validSentStatus, ExpectedStatus: 200, ExpectedResponse: "Status Update Accepted", ExpectedMsgStatus: Sp(courier.MsgSent)}, + {Label: "Unknown Sent Status Valid", URL: sentStatusURL, Data: unknownSentStatus, ExpectedStatus: 400, ExpectedResponse: "unknown sent status code", ExpectedMsgStatus: Sp(courier.MsgWired)}, + {Label: "Invalid JSON sent Status", URL: sentStatusURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, + {Label: "Missing Keys sent Status", URL: sentStatusURL, Data: missingRequiredKeys, ExpectedStatus: 400, ExpectedResponse: "validation for 'CollerationID' failed on the 'required'"}, + + {Label: "Delivered Status Valid", URL: deliveredStatusURL, Data: validDeliveredStatus, ExpectedStatus: 200, ExpectedResponse: "Status Update Accepted", ExpectedMsgStatus: Sp(courier.MsgDelivered)}, + {Label: "Unknown Delivered Status Valid", URL: deliveredStatusURL, Data: unknownDeliveredStatus, ExpectedStatus: 400, ExpectedResponse: "unknown delivered status code", ExpectedMsgStatus: Sp(courier.MsgSent)}, + {Label: "Invalid JSON delivered Statu", URL: deliveredStatusURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, + {Label: "Missing Keys sent Status", URL: deliveredStatusURL, Data: missingRequiredKeys, ExpectedStatus: 400, ExpectedResponse: "validation for 'CollerationID' failed on the 'required'"}, } func TestHandler(t *testing.T) { diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index e38019071..ea91d2a94 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -143,27 +143,27 @@ func addInvalidSignature(r *http.Request) { } var testCases = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: receiveURL, Data: validMsg, Status: 200, Response: "", - Text: Sp("Simple Message"), URN: Sp("wechat:1234"), ExternalID: Sp("123456"), - Date: Tp(time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC))}, + {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp("Simple Message"), ExpectedURN: Sp("wechat:1234"), ExpectedExternalID: Sp("123456"), + ExpectedDate: Tp(time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC))}, - {Label: "Missing params", URL: receiveURL, Data: missingParamsRequired, Status: 400, Response: "Error:Field validation"}, - {Label: "Missing params Event or MsgId", URL: receiveURL, Data: missingParams, Status: 400, Response: "missing parameters, must have either 'MsgId' or 'Event'"}, + {Label: "Missing params", URL: receiveURL, Data: missingParamsRequired, ExpectedStatus: 400, ExpectedResponse: "Error:Field validation"}, + {Label: "Missing params Event or MsgId", URL: receiveURL, Data: missingParams, ExpectedStatus: 400, ExpectedResponse: "missing parameters, must have either 'MsgId' or 'Event'"}, - {Label: "Receive Image", URL: receiveURL, Data: imageMessage, Status: 200, Response: "", - Text: Sp(""), URN: Sp("wechat:1234"), ExternalID: Sp("123456"), - Attachment: Sp("https://api.weixin.qq.com/cgi-bin/media/get?media_id=12"), - Date: Tp(time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC))}, + {Label: "Receive Image", URL: receiveURL, Data: imageMessage, ExpectedStatus: 200, ExpectedResponse: "", + ExpectedMsgText: Sp(""), ExpectedURN: Sp("wechat:1234"), ExpectedExternalID: Sp("123456"), + ExpectedAttachments: []string{"https://api.weixin.qq.com/cgi-bin/media/get?media_id=12"}, + ExpectedDate: Tp(time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC))}, - {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, Status: 200, Response: "Event Accepted", - ChannelEvent: Sp(courier.NewConversation), URN: Sp("wechat:1234")}, + {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedStatus: 200, ExpectedResponse: "Event Accepted", + ChannelEvent: Sp(courier.NewConversation), ExpectedURN: Sp("wechat:1234")}, - {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, Status: 200, Response: "unknown event"}, + {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, ExpectedStatus: 200, ExpectedResponse: "unknown event"}, - {Label: "Verify URL", URL: receiveURL, Status: 200, Response: "SUCCESS", + {Label: "Verify URL", URL: receiveURL, ExpectedStatus: 200, ExpectedResponse: "SUCCESS", PrepRequest: addValidSignature}, - {Label: "Verify URL Invalid signature", URL: receiveURL, Status: 400, Response: "unknown request", + {Label: "Verify URL Invalid signature", URL: receiveURL, ExpectedStatus: 400, ExpectedResponse: "unknown request", PrepRequest: addInvalidSignature}, } @@ -191,12 +191,12 @@ func TestFetchAccessToken(t *testing.T) { fetchTimeout = time.Millisecond RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ - {Label: "Receive Message", URL: receiveURL, Data: validMsg, Status: 200, Response: ""}, + {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: ""}, - {Label: "Verify URL", URL: receiveURL, Status: 200, Response: "SUCCESS", + {Label: "Verify URL", URL: receiveURL, ExpectedStatus: 200, ExpectedResponse: "SUCCESS", PrepRequest: addValidSignature}, - {Label: "Verify URL Invalid signature", URL: receiveURL, Status: 400, Response: "unknown request", + {Label: "Verify URL Invalid signature", URL: receiveURL, ExpectedStatus: 400, ExpectedResponse: "unknown request", PrepRequest: addInvalidSignature}, }) diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index e81e99c02..39b2f0c82 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -291,37 +291,37 @@ var ( ) var waTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: waReceiveURL, Data: helloMsg, Status: 200, Response: `"type":"msg"`, - Name: Sp("Jerry Cooney"), Text: Sp("hello world"), URN: Sp("whatsapp:250788123123"), ExternalID: Sp("41"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, - {Label: "Receive Duplicate Valid Message", URL: waReceiveURL, Data: duplicateMsg, Status: 200, Response: `"type":"msg"`, - Text: Sp("hello world"), URN: Sp("whatsapp:250788123123"), ExternalID: Sp("41"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, - {Label: "Receive Valid Audio Message", URL: waReceiveURL, Data: audioMsg, Status: 200, Response: `"type":"msg"`, - Text: Sp(""), Attachment: Sp("https://foo.bar/v1/media/41"), URN: Sp("whatsapp:250788123123"), ExternalID: Sp("41"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, - {Label: "Receive Valid Button Message", URL: waReceiveURL, Data: buttonMsg, Status: 200, Response: `"type":"msg"`, - Text: Sp("BUTTON1"), URN: Sp("whatsapp:250788123123"), ExternalID: Sp("41"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, - {Label: "Receive Valid Document Message", URL: waReceiveURL, Data: documentMsg, Status: 200, Response: `"type":"msg"`, - Text: Sp("the caption"), Attachment: Sp("https://foo.bar/v1/media/41"), URN: Sp("whatsapp:250788123123"), ExternalID: Sp("41"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, - {Label: "Receive Valid Image Message", URL: waReceiveURL, Data: imageMsg, Status: 200, Response: `"type":"msg"`, - Text: Sp("the caption"), Attachment: Sp("https://foo.bar/v1/media/41"), URN: Sp("whatsapp:250788123123"), ExternalID: Sp("41"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, - {Label: "Receive Valid Interactive Button Message", URL: waReceiveURL, Data: interactiveButtonMsg, Status: 200, Response: `"type":"msg"`, - Text: Sp("BUTTON1"), URN: Sp("whatsapp:250788123123"), ExternalID: Sp("41"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, - {Label: "Receive Valid Interactive List Message", URL: waReceiveURL, Data: interactiveListMsg, Status: 200, Response: `"type":"msg"`, - Text: Sp("ROW1"), URN: Sp("whatsapp:250788123123"), ExternalID: Sp("41"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, - {Label: "Receive Valid Location Message", URL: waReceiveURL, Data: locationMsg, Status: 200, Response: `"type":"msg"`, - Text: Sp(""), Attachment: Sp("geo:0.000000,1.000000"), URN: Sp("whatsapp:250788123123"), ExternalID: Sp("41"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, - {Label: "Receive Valid Video Message", URL: waReceiveURL, Data: videoMsg, Status: 200, Response: `"type":"msg"`, - Text: Sp(""), Attachment: Sp("https://foo.bar/v1/media/41"), URN: Sp("whatsapp:250788123123"), ExternalID: Sp("41"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, - {Label: "Receive Valid Voice Message", URL: waReceiveURL, Data: voiceMsg, Status: 200, Response: `"type":"msg"`, - Text: Sp(""), Attachment: Sp("https://foo.bar/v1/media/41"), URN: Sp("whatsapp:250788123123"), ExternalID: Sp("41"), Date: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, - {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: invalidMsg, Status: 400, Response: "unable to parse"}, - {Label: "Receive Invalid From", URL: waReceiveURL, Data: invalidFrom, Status: 400, Response: "invalid whatsapp id"}, - {Label: "Receive Invalid Timestamp", URL: waReceiveURL, Data: invalidTimestamp, Status: 400, Response: "invalid timestamp"}, + {Label: "Receive Valid Message", URL: waReceiveURL, Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + ExpectedContactName: Sp("Jerry Cooney"), ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + {Label: "Receive Duplicate Valid Message", URL: waReceiveURL, Data: duplicateMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + {Label: "Receive Valid Audio Message", URL: waReceiveURL, Data: audioMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + {Label: "Receive Valid Button Message", URL: waReceiveURL, Data: buttonMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + ExpectedMsgText: Sp("BUTTON1"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + {Label: "Receive Valid Document Message", URL: waReceiveURL, Data: documentMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + ExpectedMsgText: Sp("the caption"), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + {Label: "Receive Valid Image Message", URL: waReceiveURL, Data: imageMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + ExpectedMsgText: Sp("the caption"), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + {Label: "Receive Valid Interactive Button Message", URL: waReceiveURL, Data: interactiveButtonMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + ExpectedMsgText: Sp("BUTTON1"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + {Label: "Receive Valid Interactive List Message", URL: waReceiveURL, Data: interactiveListMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + ExpectedMsgText: Sp("ROW1"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + {Label: "Receive Valid Location Message", URL: waReceiveURL, Data: locationMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + {Label: "Receive Valid Video Message", URL: waReceiveURL, Data: videoMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + {Label: "Receive Valid Voice Message", URL: waReceiveURL, Data: voiceMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: invalidMsg, ExpectedStatus: 400, ExpectedResponse: "unable to parse"}, + {Label: "Receive Invalid From", URL: waReceiveURL, Data: invalidFrom, ExpectedStatus: 400, ExpectedResponse: "invalid whatsapp id"}, + {Label: "Receive Invalid Timestamp", URL: waReceiveURL, Data: invalidTimestamp, ExpectedStatus: 400, ExpectedResponse: "invalid timestamp"}, - {Label: "Receive Valid Status", URL: waReceiveURL, Data: validStatus, Status: 200, Response: `"type":"status"`, - MsgStatus: Sp("S"), ExternalID: Sp("9712A34B4A8B6AD50F")}, - {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: "not json", Status: 400, Response: "unable to parse"}, - {Label: "Receive Invalid Status", URL: waReceiveURL, Data: invalidStatus, Status: 400, Response: `"unknown status: in_orbit"`}, - {Label: "Receive Ignore Status", URL: waReceiveURL, Data: ignoreStatus, Status: 200, Response: `"ignoring status: deleted"`}, + {Label: "Receive Valid Status", URL: waReceiveURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `"type":"status"`, + ExpectedMsgStatus: Sp("S"), ExpectedExternalID: Sp("9712A34B4A8B6AD50F")}, + {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: "not json", ExpectedStatus: 400, ExpectedResponse: "unable to parse"}, + {Label: "Receive Invalid Status", URL: waReceiveURL, Data: invalidStatus, ExpectedStatus: 400, ExpectedResponse: `"unknown status: in_orbit"`}, + {Label: "Receive Ignore Status", URL: waReceiveURL, Data: ignoreStatus, ExpectedStatus: 200, ExpectedResponse: `"ignoring status: deleted"`}, } func TestBuildMediaRequest(t *testing.T) { diff --git a/handlers/yo/yo_test.go b/handlers/yo/yo_test.go index 9a4dd0ea0..bb2123091 100644 --- a/handlers/yo/yo_test.go +++ b/handlers/yo/yo_test.go @@ -26,18 +26,18 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729")}, - {Label: "Receive Valid From", URL: receiveValidMessageFrom, Data: "", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729")}, - {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729"), Date: Tp(time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC))}, - {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "", Status: 200, Response: "Accepted", - Text: Sp("Join"), URN: Sp("tel:+2349067554729"), Date: Tp(time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC))}, - {Label: "Invalid URN", URL: receiveInvalidURN, Data: "", Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "", Status: 400, Response: "must have one of 'sender' or 'from'"}, - {Label: "Receive No Sender", URL: receiveNoSender, Data: "", Status: 400, Response: "must have one of 'sender' or 'from'"}, - {Label: "Receive Invalid Date", URL: receiveInvalidDate, Data: "", Status: 400, Response: "invalid date format, must be RFC 3339"}, + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + {Label: "Receive Valid From", URL: receiveValidMessageFrom, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: Tp(time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC))}, + {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: Tp(time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC))}, + {Label: "Invalid URN", URL: receiveInvalidURN, Data: "", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Receive No Params", URL: receiveNoParams, Data: "", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from'"}, + {Label: "Receive No Sender", URL: receiveNoSender, Data: "", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from'"}, + {Label: "Receive Invalid Date", URL: receiveInvalidDate, Data: "", ExpectedStatus: 400, ExpectedResponse: "invalid date format, must be RFC 3339"}, } func TestHandler(t *testing.T) { diff --git a/handlers/zenvia/zenvia_test.go b/handlers/zenvia/zenvia_test.go index 3f34baf82..8dddffb75 100644 --- a/handlers/zenvia/zenvia_test.go +++ b/handlers/zenvia/zenvia_test.go @@ -196,45 +196,45 @@ var missingFieldsReceive = `{ }` var testWhatappCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveWhatsappURL, Data: validReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Msg"), URN: Sp("whatsapp:254791541111"), Date: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, + {Label: "Receive Valid", URL: receiveWhatsappURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, - {Label: "Receive file Valid", URL: receiveWhatsappURL, Data: fileReceive, Status: 200, Response: "Message Accepted", - Text: Sp(""), Attachment: Sp("https://foo.bar/v1/media/41"), URN: Sp("whatsapp:254791541111"), Date: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, + {Label: "Receive file Valid", URL: receiveWhatsappURL, Data: fileReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, - {Label: "Receive location Valid", URL: receiveWhatsappURL, Data: locationReceive, Status: 200, Response: "Message Accepted", - Text: Sp(""), Attachment: Sp("geo:0.000000,1.000000"), URN: Sp("whatsapp:254791541111"), Date: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, + {Label: "Receive location Valid", URL: receiveWhatsappURL, Data: locationReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, - {Label: "Not JSON body", URL: receiveWhatsappURL, Data: notJSON, Status: 400, Response: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: receiveWhatsappURL, Data: wrongJSONSchema, Status: 400, Response: "request JSON doesn't match required schema"}, - {Label: "Missing field", URL: receiveWhatsappURL, Data: missingFieldsReceive, Status: 400, Response: "validation for 'ID' failed on the 'required'"}, - {Label: "Bad Date", URL: receiveWhatsappURL, Data: invalidDateReceive, Status: 400, Response: "invalid date format"}, + {Label: "Not JSON body", URL: receiveWhatsappURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: receiveWhatsappURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, + {Label: "Missing field", URL: receiveWhatsappURL, Data: missingFieldsReceive, ExpectedStatus: 400, ExpectedResponse: "validation for 'ID' failed on the 'required'"}, + {Label: "Bad Date", URL: receiveWhatsappURL, Data: invalidDateReceive, ExpectedStatus: 400, ExpectedResponse: "invalid date format"}, - {Label: "Valid Status", URL: statusWhatsppURL, Data: validStatus, Status: 200, Response: `Accepted`, MsgStatus: Sp("S")}, - {Label: "Unkown Status", URL: statusWhatsppURL, Data: unknownStatus, Status: 200, Response: "Accepted", MsgStatus: Sp("E")}, - {Label: "Not JSON body", URL: statusWhatsppURL, Data: notJSON, Status: 400, Response: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: statusWhatsppURL, Data: wrongJSONSchema, Status: 400, Response: "request JSON doesn't match required schema"}, + {Label: "Valid Status", URL: statusWhatsppURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `Accepted`, ExpectedMsgStatus: Sp("S")}, + {Label: "Unkown Status", URL: statusWhatsppURL, Data: unknownStatus, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgStatus: Sp("E")}, + {Label: "Not JSON body", URL: statusWhatsppURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: statusWhatsppURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, } var testSMSCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveSMSURL, Data: validReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Msg"), URN: Sp("whatsapp:254791541111"), Date: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, + {Label: "Receive Valid", URL: receiveSMSURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, - {Label: "Receive file Valid", URL: receiveSMSURL, Data: fileReceive, Status: 200, Response: "Message Accepted", - Text: Sp(""), Attachment: Sp("https://foo.bar/v1/media/41"), URN: Sp("whatsapp:254791541111"), Date: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, + {Label: "Receive file Valid", URL: receiveSMSURL, Data: fileReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, - {Label: "Receive location Valid", URL: receiveSMSURL, Data: locationReceive, Status: 200, Response: "Message Accepted", - Text: Sp(""), Attachment: Sp("geo:0.000000,1.000000"), URN: Sp("whatsapp:254791541111"), Date: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, + {Label: "Receive location Valid", URL: receiveSMSURL, Data: locationReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, - {Label: "Not JSON body", URL: receiveSMSURL, Data: notJSON, Status: 400, Response: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: receiveSMSURL, Data: wrongJSONSchema, Status: 400, Response: "request JSON doesn't match required schema"}, - {Label: "Missing field", URL: receiveSMSURL, Data: missingFieldsReceive, Status: 400, Response: "validation for 'ID' failed on the 'required'"}, - {Label: "Bad Date", URL: receiveSMSURL, Data: invalidDateReceive, Status: 400, Response: "invalid date format"}, + {Label: "Not JSON body", URL: receiveSMSURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: receiveSMSURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, + {Label: "Missing field", URL: receiveSMSURL, Data: missingFieldsReceive, ExpectedStatus: 400, ExpectedResponse: "validation for 'ID' failed on the 'required'"}, + {Label: "Bad Date", URL: receiveSMSURL, Data: invalidDateReceive, ExpectedStatus: 400, ExpectedResponse: "invalid date format"}, - {Label: "Valid Status", URL: statusSMSURL, Data: validStatus, Status: 200, Response: `Accepted`, MsgStatus: Sp("S")}, - {Label: "Unkown Status", URL: statusSMSURL, Data: unknownStatus, Status: 200, Response: "Accepted", MsgStatus: Sp("E")}, - {Label: "Not JSON body", URL: statusSMSURL, Data: notJSON, Status: 400, Response: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: statusSMSURL, Data: wrongJSONSchema, Status: 400, Response: "request JSON doesn't match required schema"}, + {Label: "Valid Status", URL: statusSMSURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `Accepted`, ExpectedMsgStatus: Sp("S")}, + {Label: "Unkown Status", URL: statusSMSURL, Data: unknownStatus, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgStatus: Sp("E")}, + {Label: "Not JSON body", URL: statusSMSURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: statusSMSURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, } func TestHandler(t *testing.T) { diff --git a/handlers/zenviaold/zenviaold_test.go b/handlers/zenviaold/zenviaold_test.go index c9cd83565..b8001840d 100644 --- a/handlers/zenviaold/zenviaold_test.go +++ b/handlers/zenviaold/zenviaold_test.go @@ -105,21 +105,21 @@ var missingFieldsReceive = `{ }` var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, Status: 200, Response: "Message Accepted", - Text: Sp("Msg"), URN: Sp("tel:+254791541111"), Date: Tp(time.Date(2017, 5, 3, 06, 04, 45, 123000000, time.UTC))}, - - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, Status: 400, Response: "phone number supplied is not a number"}, - {Label: "Not JSON body", URL: receiveURL, Data: notJSON, Status: 400, Response: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: receiveURL, Data: wrongJSONSchema, Status: 400, Response: "request JSON doesn't match required schema"}, - {Label: "Missing field", URL: receiveURL, Data: missingFieldsReceive, Status: 400, Response: "validation for 'ID' failed on the 'required'"}, - {Label: "Bad Date", URL: receiveURL, Data: invalidDateReceive, Status: 400, Response: "invalid date format"}, - - {Label: "Valid Status", URL: statusURL, Data: validStatus, Status: 200, Response: `Accepted`, MsgStatus: Sp("D")}, - {Label: "Valid Status with more fields", URL: statusURL, Data: validWithMoreFieldsStatus, Status: 200, Response: `Accepted`, MsgStatus: Sp("D")}, - {Label: "Unkown Status", URL: statusURL, Data: unknownStatus, Status: 200, Response: "Accepted", MsgStatus: Sp("E")}, - {Label: "Not JSON body", URL: statusURL, Data: notJSON, Status: 400, Response: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: statusURL, Data: wrongJSONSchema, Status: 400, Response: "request JSON doesn't match required schema"}, - {Label: "Missing field", URL: statusURL, Data: missingFieldsStatus, Status: 400, Response: "validation for 'StatusCode' failed on the 'required'"}, + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111"), ExpectedDate: Tp(time.Date(2017, 5, 3, 06, 04, 45, 123000000, time.UTC))}, + + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Not JSON body", URL: receiveURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: receiveURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, + {Label: "Missing field", URL: receiveURL, Data: missingFieldsReceive, ExpectedStatus: 400, ExpectedResponse: "validation for 'ID' failed on the 'required'"}, + {Label: "Bad Date", URL: receiveURL, Data: invalidDateReceive, ExpectedStatus: 400, ExpectedResponse: "invalid date format"}, + + {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `Accepted`, ExpectedMsgStatus: Sp("D")}, + {Label: "Valid Status with more fields", URL: statusURL, Data: validWithMoreFieldsStatus, ExpectedStatus: 200, ExpectedResponse: `Accepted`, ExpectedMsgStatus: Sp("D")}, + {Label: "Unkown Status", URL: statusURL, Data: unknownStatus, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgStatus: Sp("E")}, + {Label: "Not JSON body", URL: statusURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: statusURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, + {Label: "Missing field", URL: statusURL, Data: missingFieldsStatus, ExpectedStatus: 400, ExpectedResponse: "validation for 'StatusCode' failed on the 'required'"}, } func TestHandler(t *testing.T) { From 4952749970849568dc76c680e04ba14d0d97292a Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 11 Aug 2022 09:37:49 -0500 Subject: [PATCH 062/294] Rename S3MediaBucket to S3AttachmentsBucket and S3MediaPrefix to S3AttachmentsPrefix --- backends/rapidpro/backend.go | 2 +- backends/rapidpro/msg.go | 2 +- config.go | 36 ++++++++++++++++++------------------ courier.toml | 4 ++-- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 8b9e78103..fb83a3ce4 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -728,7 +728,7 @@ func (b *backend) Start() error { if err != nil { return err } - b.storage = storage.NewS3(s3Client, b.config.S3MediaBucket, b.config.S3Region, 32) + b.storage = storage.NewS3(s3Client, b.config.S3AttachmentsBucket, b.config.S3Region, 32) } else { b.storage = storage.NewFS("_storage") } diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index 92460a9a5..6f7bad950 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -295,7 +295,7 @@ func downloadMediaToS3(ctx context.Context, b *backend, channel courier.Channel, if extension != "" { filename = fmt.Sprintf("%s.%s", msgUUID, extension) } - path := filepath.Join(b.config.S3MediaPrefix, strconv.FormatInt(int64(orgID), 10), filename[:4], filename[4:8], filename) + path := filepath.Join(b.config.S3AttachmentsPrefix, strconv.FormatInt(int64(orgID), 10), filename[:4], filename[4:8], filename) if !strings.HasPrefix(path, "/") { path = fmt.Sprintf("/%s", path) } diff --git a/config.go b/config.go index 16188bcc2..c6f62433f 100644 --- a/config.go +++ b/config.go @@ -15,15 +15,15 @@ type Config struct { Redis string `help:"URL describing how to connect to Redis"` SpoolDir string `help:"the local directory where courier will write statuses or msgs that need to be retried (needs to be writable)"` - AWSAccessKeyID string `help:"the access key id to use when authenticating S3"` - AWSSecretAccessKey string `help:"the secret access key id to use when authenticating S3"` - AWSUseCredChain bool `help:"whether to use the AWS credentials chain. Defaults to false."` - S3Endpoint string `help:"the S3 endpoint we will write attachments to"` - S3Region string `help:"the S3 region we will write attachments to"` - S3MediaBucket string `help:"the S3 bucket we will write attachments to"` - S3MediaPrefix string `help:"the prefix that will be added to attachment filenames"` - S3DisableSSL bool `help:"whether we disable SSL when accessing S3. Should always be set to False unless you're hosting an S3 compatible service within a secure internal network"` - S3ForcePathStyle bool `help:"whether we force S3 path style. Should generally need to default to False unless you're hosting an S3 compatible service"` + AWSAccessKeyID string `help:"the access key id to use when authenticating S3"` + AWSSecretAccessKey string `help:"the secret access key id to use when authenticating S3"` + AWSUseCredChain bool `help:"whether to use the AWS credentials chain. Defaults to false."` + S3Endpoint string `help:"the S3 endpoint we will write attachments to"` + S3Region string `help:"the S3 region we will write attachments to"` + S3AttachmentsBucket string `help:"the S3 bucket we will write attachments to"` + S3AttachmentsPrefix string `help:"the prefix that will be added to attachment filenames"` + S3DisableSSL bool `help:"whether we disable SSL when accessing S3. Should always be set to False unless you're hosting an S3 compatible service within a secure internal network"` + S3ForcePathStyle bool `help:"whether we force S3 path style. Should generally need to default to False unless you're hosting an S3 compatible service"` FacebookApplicationSecret string `help:"the Facebook app secret"` FacebookWebhookSecret string `help:"the secret for Facebook webhook URL verification"` @@ -56,15 +56,15 @@ func NewConfig() *Config { Redis: "redis://localhost:6379/15", SpoolDir: "/var/spool/courier", - AWSAccessKeyID: "", - AWSSecretAccessKey: "", - AWSUseCredChain: false, - S3Endpoint: "https://s3.amazonaws.com", - S3Region: "us-east-1", - S3MediaBucket: "courier-media", - S3MediaPrefix: "/media/", - S3DisableSSL: false, - S3ForcePathStyle: false, + AWSAccessKeyID: "", + AWSSecretAccessKey: "", + AWSUseCredChain: false, + S3Endpoint: "https://s3.amazonaws.com", + S3Region: "us-east-1", + S3AttachmentsBucket: "courier-media", + S3AttachmentsPrefix: "/media/", + S3DisableSSL: false, + S3ForcePathStyle: false, FacebookApplicationSecret: "missing_facebook_app_secret", FacebookWebhookSecret: "missing_facebook_webhook_secret", diff --git a/courier.toml b/courier.toml index 90cf43f51..103f5c401 100644 --- a/courier.toml +++ b/courier.toml @@ -32,10 +32,10 @@ aws_secret_access_key = "" s3_region = "us-east-2" # The S3 bucket we will write our media files to -s3_media_bucket = "courier-test" +s3_attachments_bucket = "courier-test" # prefix to our filenames for media (files will be named after the msg uuid) -s3_media_prefix = "media" +s3_attachments_prefix = "media" # the DSN token for reporting errors to sentry sentry_dsn = "" From ffeb6731674a9e99817aa92b3bb8bb939712a630 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 11 Aug 2022 10:13:34 -0500 Subject: [PATCH 063/294] Update CHANGELOG.md for v7.5.9 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f34f574a..cbae67f32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.9 +---------- + * Rename S3MediaBucket to S3AttachmentsBucket and S3MediaPrefix to S3AttachmentsPrefix + * More handlers to use new HTTP functions + v7.5.8 ---------- * Move testing code out of courier package and into new test package From 04cb120fe29b390b72b4bcba96cc4a5be6ccc776 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 11 Aug 2022 12:00:35 -0500 Subject: [PATCH 064/294] Update nexmo, jiochat and telegram sending to use channel logger --- handlers/jiochat/jiochat.go | 12 ++-- handlers/jiochat/jiochat_test.go | 39 ++++++----- handlers/nexmo/nexmo.go | 21 +++--- handlers/nexmo/nexmo_test.go | 114 ++++++++++++++++++++----------- handlers/telegram/telegram.go | 77 +++++++++------------ 5 files changed, 146 insertions(+), 117 deletions(-) diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 4b46106df..085dc56c7 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -263,15 +263,11 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken)) - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - - if err != nil { - return status, err + resp, _, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return status, nil } + status.SetStatus(courier.MsgWired) } diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index b093ecc20..6674ec2cb 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -325,11 +325,10 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", + { + Label: "Plain Send", MsgText: "Simple Message ☺", MsgURN: "jiochat:12345", - ExpectedStatus: "W", - ExpectedExternalID: "", MockResponseStatus: 200, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", @@ -337,12 +336,14 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Bearer ACCESS_TOKEN", }, ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"Simple Message ☺"}}`, - SendPrep: setSendURL}, - {Label: "Long Send", + ExpectedStatus: "W", + ExpectedExternalID: "", + SendPrep: setSendURL, + }, + { + Label: "Long Send", MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", MsgURN: "jiochat:12345", - ExpectedStatus: "W", - ExpectedExternalID: "", MockResponseStatus: 200, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", @@ -350,13 +351,15 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Bearer ACCESS_TOKEN", }, ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"I need to keep adding more things to make it work"}}`, - SendPrep: setSendURL}, - {Label: "Send Attachment", + ExpectedStatus: "W", + ExpectedExternalID: "", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", MsgText: "My pic!", MsgURN: "jiochat:12345", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - ExpectedExternalID: "", MockResponseStatus: 200, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", @@ -364,14 +367,18 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Bearer ACCESS_TOKEN", }, ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"My pic!\nhttps://foo.bar/image.jpg"}}`, - SendPrep: setSendURL}, - {Label: "Error Sending", + ExpectedStatus: "W", + ExpectedExternalID: "", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", MsgText: "Error Message", MsgURN: "jiochat:12345", - ExpectedStatus: "E", MockResponseStatus: 401, - ExpectedErrors: []string{"received non 200 status: 401"}, - SendPrep: setSendURL}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } func setupBackend(mb *test.MockBackend) { diff --git a/handlers/nexmo/nexmo.go b/handlers/nexmo/nexmo.go index 929845e6a..a01b6d4e3 100644 --- a/handlers/nexmo/nexmo.go +++ b/handlers/nexmo/nexmo.go @@ -13,7 +13,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/gocommon/gsm7" - "github.com/nyaruka/gocommon/httpx" "github.com/buger/jsonparser" "github.com/pkg/errors" @@ -153,8 +152,10 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha "type": []string{textType}, } - var trace *httpx.Trace + var resp *http.Response + var respBody []byte var requestErr error + for i := 0; i < 3; i++ { req, err := http.NewRequest(http.MethodPost, sendURL, strings.NewReader(form.Encode())) if err != nil { @@ -162,8 +163,8 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - trace, requestErr = handlers.MakeHTTPRequest(req) - matched := throttledRE.FindAllStringSubmatch(string(trace.ResponseBody), -1) + resp, respBody, requestErr = handlers.RequestHTTP(req, logger) + matched := throttledRE.FindAllStringSubmatch(string(respBody), -1) if len(matched) > 0 && len(matched[0]) > 0 { sleepTime, _ := strconv.Atoi(matched[0][1]) time.Sleep(time.Duration(sleepTime) * time.Millisecond) @@ -172,21 +173,17 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } } - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace) - status.AddLog(log) - if requestErr != nil { - log.WithError("Message Send Error", requestErr) + if requestErr != nil || resp.StatusCode/100 != 2 { return status, nil } - nexmoStatus, err := jsonparser.GetString(trace.ResponseBody, "messages", "[0]", "status") + nexmoStatus, err := jsonparser.GetString(respBody, "messages", "[0]", "status") if err != nil || nexmoStatus != "0" { - log.WithError("Message Send Error", errors.Errorf("failed to send message, received error status [%s]", nexmoStatus)) + logger.Error(errors.Errorf("failed to send message, received error status [%s]", nexmoStatus)) return status, nil } - externalID, err := jsonparser.GetString(trace.ResponseBody, "messages", "[0]", "message-id") + externalID, err := jsonparser.GetString(respBody, "messages", "[0]", "message-id") if err == nil { status.SetExternalID(externalID) } diff --git a/handlers/nexmo/nexmo_test.go b/handlers/nexmo/nexmo_test.go index 0e5b2fb4f..590662af5 100644 --- a/handlers/nexmo/nexmo_test.go +++ b/handlers/nexmo/nexmo_test.go @@ -60,55 +60,93 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", ExpectedExternalID: "1002", + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, + MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - MockResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: "Unicode ☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", ExpectedExternalID: "1002", + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "Unicode ☺", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, + MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Unicode ☺", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "unicode"}, - MockResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Long Send", - MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - MsgURN: "tel:+250788383383", - ExpectedStatus: "W", ExpectedExternalID: "1002", + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Long Send", + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, + MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "I need to keep adding more things to make it work", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - MockResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", ExpectedExternalID: "1002", + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, + MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - MockResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Error Status", - MsgText: "Error status", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", + ExpectedStatus: "W", + ExpectedExternalID: "1002", + SendPrep: setSendURL, + }, + { + Label: "Error Status", + MsgText: "Error status", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"messages":[{"status":"10"}]}`, + MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Error status", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - MockResponseBody: `{"messages":[{"status":"10"}]}`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", ExpectedStatus: "E", + ExpectedErrors: []string{"failed to send message, received error status [10]"}, + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `Error`, + MockResponseStatus: 400, ExpectedPostParams: map[string]string{"text": "Error Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - MockResponseBody: `Error`, MockResponseStatus: 400, - SendPrep: setSendURL}, - {Label: "Invalid Token", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Invalid Token", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: "Invalid API token", + MockResponseStatus: 401, ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - MockResponseBody: "Invalid API token", MockResponseStatus: 401, - SendPrep: setSendURL}, - {Label: "Throttled by Nexmo", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Throttled by Nexmo", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"messages":[{"status":"1","error-text":"Throughput Rate Exceeded - please wait [ 250 ] and retry"}]}`, + MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - MockResponseBody: `{"messages":[{"status":"1","error-text":"Throughput Rate Exceeded - please wait [ 250 ] and retry"}]}`, MockResponseStatus: 200, - SendPrep: setSendURL}, + ExpectedStatus: "E", + ExpectedErrors: []string{"failed to send message, received error status [1]"}, + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index c070a6b7e..2e7be389e 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -149,7 +149,7 @@ type mtResponse struct { } `json:"result"` } -func (h *handler) sendMsgPart(msg courier.Msg, token string, path string, form url.Values, keyboard *ReplyKeyboardMarkup) (string, *courier.ChannelLog, bool, error) { +func (h *handler) sendMsgPart(msg courier.Msg, token string, path string, form url.Values, keyboard *ReplyKeyboardMarkup, logger *courier.ChannelLogger) (string, bool, error) { // either include or remove our keyboard if keyboard == nil { form.Add("reply_markup", `{"remove_keyboard":true}`) @@ -160,31 +160,27 @@ func (h *handler) sendMsgPart(msg courier.Msg, token string, path string, form u sendURL := fmt.Sprintf("%s/bot%s/%s", apiURL, token, path) req, err := http.NewRequest(http.MethodPost, sendURL, strings.NewReader(form.Encode())) if err != nil { - return "", nil, false, err + return "", false, err } req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - trace, err := handlers.MakeHTTPRequest(req) - - // build our channel log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) + resp, respBody, _ := handlers.RequestHTTP(req, logger) response := &mtResponse{} - err = json.Unmarshal(trace.ResponseBody, response) + err = json.Unmarshal(respBody, response) - if err != nil || !response.Ok { + if err != nil || resp.StatusCode/100 != 2 || !response.Ok { if response.ErrorCode == 403 && response.Description == "Forbidden: bot was blocked by the user" { - return "", log, true, errors.Errorf("response not 'ok'") - + return "", true, errors.Errorf("response not 'ok'") } - return "", log, false, errors.Errorf("response not 'ok'") + return "", false, errors.Errorf("response not 'ok'") } if response.Result.MessageID > 0 { - return strconv.FormatInt(response.Result.MessageID, 10), log, false, nil + return strconv.FormatInt(response.Result.MessageID, 10), false, nil } - return "", log, false, errors.Errorf("no 'result.message_id' in response") + return "", false, errors.Errorf("no 'result.message_id' in response") } // Send sends the given message, logging any HTTP calls or errors @@ -231,8 +227,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha "text": []string{msg.Text()}, } - externalID, log, botBlocked, err := h.sendMsgPart(msg, authToken, "sendMessage", form, msgKeyBoard) - status.AddLog(log) + externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendMessage", form, msgKeyBoard, logger) if botBlocked { status.SetStatus(courier.MsgFailed) channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) @@ -258,8 +253,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha "photo": []string{attachment.URL}, "caption": []string{caption}, } - externalID, log, botBlocked, err := h.sendMsgPart(msg, authToken, "sendPhoto", form, attachmentKeyBoard) - status.AddLog(log) + externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendPhoto", form, attachmentKeyBoard, logger) if botBlocked { status.SetStatus(courier.MsgFailed) channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) @@ -275,8 +269,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha "video": []string{attachment.URL}, "caption": []string{caption}, } - externalID, log, botBlocked, err := h.sendMsgPart(msg, authToken, "sendVideo", form, attachmentKeyBoard) - status.AddLog(log) + externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendVideo", form, attachmentKeyBoard, logger) if botBlocked { status.SetStatus(courier.MsgFailed) channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) @@ -292,8 +285,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha "audio": []string{attachment.URL}, "caption": []string{caption}, } - externalID, log, botBlocked, err := h.sendMsgPart(msg, authToken, "sendAudio", form, attachmentKeyBoard) - status.AddLog(log) + externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendAudio", form, attachmentKeyBoard, logger) if botBlocked { status.SetStatus(courier.MsgFailed) channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) @@ -309,8 +301,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha "document": []string{attachment.URL}, "caption": []string{caption}, } - externalID, log, botBlocked, err := h.sendMsgPart(msg, authToken, "sendDocument", form, attachmentKeyBoard) - status.AddLog(log) + externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendDocument", form, attachmentKeyBoard, logger) if botBlocked { status.SetStatus(courier.MsgFailed) channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) @@ -390,26 +381,26 @@ type moLocation struct { Longitude float64 `json:"longitude"` } -// { -// "update_id": 174114370, -// "message": { -// "message_id": 41, -// "from": { -// "id": 3527065, -// "first_name": "Nic", -// "last_name": "Pottier", -// "username": "nicpottier" -// }, -// "chat": { -// "id": 3527065, -// "first_name": "Nic", -// "last_name": "Pottier", -// "type": "private" -// }, -// "date": 1454119029, -// "text": "Hello World" -// } -// } +// { +// "update_id": 174114370, +// "message": { +// "message_id": 41, +// "from": { +// "id": 3527065, +// "first_name": "Nic", +// "last_name": "Pottier", +// "username": "nicpottier" +// }, +// "chat": { +// "id": 3527065, +// "first_name": "Nic", +// "last_name": "Pottier", +// "type": "private" +// }, +// "date": 1454119029, +// "text": "Hello World" +// } +// } type moPayload struct { UpdateID int64 `json:"update_id" validate:"required"` Message struct { From 313d2307ab06d250ff03e21d239658bba55edb4e Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 11 Aug 2022 15:56:29 -0500 Subject: [PATCH 065/294] Rework handler DescribeURN methods to take a channel logger --- backends/rapidpro/contact.go | 5 +- channel_log.go | 24 ++++--- handler.go | 2 +- handlers/facebook/facebook.go | 80 ++++++++++++------------ handlers/facebook/facebook_test.go | 17 +++-- handlers/facebookapp/facebookapp.go | 47 +++++++------- handlers/facebookapp/facebookapp_test.go | 50 +++++++++------ handlers/jiochat/jiochat.go | 12 ++-- handlers/jiochat/jiochat_test.go | 11 ++-- handlers/slack/slack.go | 10 +-- handlers/slack/slack_test.go | 5 +- handlers/vk/vk.go | 12 ++-- handlers/vk/vk_test.go | 12 ++-- handlers/wechat/wechat.go | 24 ++++--- handlers/wechat/wechat_test.go | 52 ++++++++------- 15 files changed, 201 insertions(+), 162 deletions(-) diff --git a/backends/rapidpro/contact.go b/backends/rapidpro/contact.go index 831dedb28..373621ba5 100644 --- a/backends/rapidpro/contact.go +++ b/backends/rapidpro/contact.go @@ -139,7 +139,10 @@ func contactForURN(ctx context.Context, b *backend, org OrgID, channel *DBChanne if handler != nil { describer, isDescriber := handler.(courier.URNDescriber) if isDescriber { - atts, err := describer.DescribeURN(ctx, channel, urn) + // TODO: this should be created by the server and passed down + logger := courier.NewChannelLoggerForReceive(channel) + + atts, err := describer.DescribeURN(ctx, channel, urn, logger) // in the case of errors, we log the error but move onwards anyways if err != nil { diff --git a/channel_log.go b/channel_log.go index 303465479..f159cf825 100644 --- a/channel_log.go +++ b/channel_log.go @@ -116,26 +116,34 @@ type ChannelLog struct { type ChannelLogType string const ( - ChannelLogTypeSend ChannelLogType = "send" + ChannelLogTypeMessageSend ChannelLogType = "message_send" + ChannelLogTypeMessageReceive ChannelLogType = "message_receive" ) var logTypeDescriptions = map[ChannelLogType]string{ - ChannelLogTypeSend: "Message Send", + ChannelLogTypeMessageSend: "Message Sent", + ChannelLogTypeMessageReceive: "Message Received", } var logTypeErrorDescriptions = map[ChannelLogType]string{ - ChannelLogTypeSend: "Message Send Error", + ChannelLogTypeMessageSend: "Message Sending Error", + ChannelLogTypeMessageReceive: "Message Receive Error", } type ChannelLogger struct { - type_ ChannelLogType - msg Msg + type_ ChannelLogType + channel Channel + msgID MsgID errors []string logs []*ChannelLog } func NewChannelLoggerForSend(msg Msg) *ChannelLogger { - return &ChannelLogger{type_: ChannelLogTypeSend, msg: msg} + return &ChannelLogger{type_: ChannelLogTypeMessageSend, channel: msg.Channel(), msgID: msg.ID()} +} + +func NewChannelLoggerForReceive(channel Channel) *ChannelLogger { + return &ChannelLogger{type_: ChannelLogTypeMessageSend, channel: channel} } // HTTP logs an HTTP request and response @@ -147,7 +155,7 @@ func (l *ChannelLogger) HTTP(t *httpx.Trace) { description = logTypeDescriptions[l.type_] } - l.logs = append(l.logs, NewChannelLogFromTrace(description, l.msg.Channel(), l.msg.ID(), t)) + l.logs = append(l.logs, NewChannelLogFromTrace(description, l.channel, l.msgID, t)) } func (l *ChannelLogger) Error(err error) { @@ -158,7 +166,7 @@ func (l *ChannelLogger) Error(err error) { l.logs[len(l.logs)-1].Error = err.Error() l.logs[len(l.logs)-1].Description = logTypeErrorDescriptions[l.type_] } else { - l.logs = append(l.logs, NewChannelLogFromError(logTypeErrorDescriptions[l.type_], l.msg.Channel(), l.msg.ID(), 0, err)) + l.logs = append(l.logs, NewChannelLogFromError(logTypeErrorDescriptions[l.type_], l.channel, l.msgID, 0, err)) } } diff --git a/handler.go b/handler.go index f34b23e09..fb0277f5b 100644 --- a/handler.go +++ b/handler.go @@ -30,7 +30,7 @@ type ChannelHandler interface { // URNDescriber is the interface handlers which can look up URN metadata for new contacts should satisfy. type URNDescriber interface { - DescribeURN(context.Context, Channel, urns.URN) (map[string]string, error) + DescribeURN(context.Context, Channel, urns.URN, *ChannelLogger) (map[string]string, error) } // MediaDownloadRequestBuilder is the interface handlers which can allow a custom way to download attachment media for messages should satisfy diff --git a/handlers/facebook/facebook.go b/handlers/facebook/facebook.go index 519e4fab5..92d463412 100644 --- a/handlers/facebook/facebook.go +++ b/handlers/facebook/facebook.go @@ -126,23 +126,25 @@ type fbUser struct { ID string `json:"id"` } -// { -// "object":"page", -// "entry":[{ -// "id":"180005062406476", -// "time":1514924367082, -// "messaging":[{ -// "sender": {"id":"1630934236957797"}, -// "recipient":{"id":"180005062406476"}, -// "timestamp":1514924366807, -// "message":{ -// "mid":"mid.$cAAD5QiNHkz1m6cyj11guxokwkhi2", -// "seq":33116, -// "text":"65863634" -// } -// }] -// }] -// } +// { +// "object":"page", +// "entry":[{ +// "id":"180005062406476", +// "time":1514924367082, +// "messaging":[ +// { +// "sender": {"id":"1630934236957797"}, +// "recipient":{"id":"180005062406476"}, +// "timestamp":1514924366807, +// "message":{ +// "mid":"mid.$cAAD5QiNHkz1m6cyj11guxokwkhi2", +// "seq":33116, +// "text":"65863634" +// } +// } +// ] +// }] +// } type moPayload struct { Object string `json:"object"` Entry []struct { @@ -427,22 +429,22 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return events, courier.WriteDataResponse(ctx, w, http.StatusOK, "Events Handled", data) } -// { -// "messaging_type": "" -// "recipient":{ -// "id":"" -// }, -// "message":{ -// "text":"hello, world!" -// "attachment":{ -// "type":"image", -// "payload":{ -// "url":"http://www.messenger-rocks.com/image.jpg", -// "is_reusable":true -// } -// } -// } -// } +// { +// "messaging_type": "" +// "recipient": { +// "id":"" +// }, +// "message": { +// "text":"hello, world!" +// "attachment":{ +// "type":"image", +// "payload":{ +// "url":"http://www.messenger-rocks.com/image.jpg", +// "is_reusable":true +// } +// } +// } +// } type mtPayload struct { MessagingType string `json:"messaging_type"` Tag string `json:"tag,omitempty"` @@ -619,7 +621,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } // DescribeURN looks up URN metadata for new contacts -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, logger *courier.ChannelLogger) (map[string]string, error) { // can't do anything with facebook refs, ignore them if urn.IsFacebookRef() { return map[string]string{}, nil @@ -641,14 +643,14 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn u.RawQuery = query.Encode() req, _ := http.NewRequest(http.MethodGet, u.String(), nil) - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - return nil, fmt.Errorf("unable to look up contact data: %s", err) + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return nil, errors.New("unable to look up contact data") } // read our first and last name - firstName, _ := jsonparser.GetString(trace.ResponseBody, "first_name") - lastName, _ := jsonparser.GetString(trace.ResponseBody, "last_name") + firstName, _ := jsonparser.GetString(respBody, "first_name") + lastName, _ := jsonparser.GetString(respBody, "last_name") return map[string]string{"name": utils.JoinNonEmpty(" ", firstName, lastName)}, nil } diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index c4a438a04..ec48eebe4 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -493,17 +493,22 @@ func TestDescribe(t *testing.T) { fbGraph := buildMockFBGraph(testCases) defer fbGraph.Close() + channel := testChannels[0] handler := newHandler().(courier.URNDescriber) + logger := courier.NewChannelLoggerForReceive(channel) + tcs := []struct { - urn urns.URN - metadata map[string]string - }{{"facebook:1337", map[string]string{"name": "John Doe"}}, + urn urns.URN + expectedMetadata map[string]string + }{ + {"facebook:1337", map[string]string{"name": "John Doe"}}, {"facebook:4567", map[string]string{"name": ""}}, - {"facebook:ref:1337", map[string]string{}}} + {"facebook:ref:1337", map[string]string{}}, + } for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), testChannels[0], tc.urn) - assert.Equal(t, metadata, tc.metadata) + metadata, _ := handler.DescribeURN(context.Background(), channel, tc.urn, logger) + assert.Equal(t, metadata, tc.expectedMetadata) } } diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 5043e63d2..79b92cfc6 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -759,22 +759,22 @@ func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel c return events, data, nil } -// { -// "messaging_type": "" -// "recipient":{ -// "id":"" -// }, -// "message":{ -// "text":"hello, world!" -// "attachment":{ -// "type":"image", -// "payload":{ -// "url":"http://www.messenger-rocks.com/image.jpg", -// "is_reusable":true -// } -// } -// } -// } +// { +// "messaging_type": "" +// "recipient": { +// "id":"" +// }, +// "message": { +// "text":"hello, world!" +// "attachment":{ +// "type":"image", +// "payload":{ +// "url":"http://www.messenger-rocks.com/image.jpg", +// "is_reusable":true +// } +// } +// } +// } type mtPayload struct { MessagingType string `json:"messaging_type"` Tag string `json:"tag,omitempty"` @@ -1305,10 +1305,9 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg) } // DescribeURN looks up URN metadata for new contacts -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, logger *courier.ChannelLogger) (map[string]string, error) { if channel.ChannelType() == "WAC" { return map[string]string{}, nil - } // can't do anything with facebook refs, ignore them @@ -1336,18 +1335,18 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn u.RawQuery = query.Encode() req, _ := http.NewRequest(http.MethodGet, u.String(), nil) - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - return nil, fmt.Errorf("unable to look up contact data: %s", err) + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return nil, errors.New("unable to look up contact data") } // read our first and last name or complete name if fmt.Sprint(channel.ChannelType()) == "FBA" { - firstName, _ := jsonparser.GetString(trace.ResponseBody, "first_name") - lastName, _ := jsonparser.GetString(trace.ResponseBody, "last_name") + firstName, _ := jsonparser.GetString(respBody, "first_name") + lastName, _ := jsonparser.GetString(respBody, "last_name") name = utils.JoinNonEmpty(" ", firstName, lastName) } else { - name, _ = jsonparser.GetString(trace.ResponseBody, "name") + name, _ = jsonparser.GetString(respBody, "name") } return map[string]string{"name": name}, nil diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 23bcfd798..15adc038f 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -188,17 +188,22 @@ func TestDescribeFBA(t *testing.T) { fbGraph := buildMockFBGraphFBA(testCasesFBA) defer fbGraph.Close() + channel := testChannelsFBA[0] handler := newHandler("FBA", "Facebook", false).(courier.URNDescriber) + logger := courier.NewChannelLoggerForReceive(channel) + tcs := []struct { - urn urns.URN - metadata map[string]string - }{{"facebook:1337", map[string]string{"name": "John Doe"}}, + urn urns.URN + expectedMetadata map[string]string + }{ + {"facebook:1337", map[string]string{"name": "John Doe"}}, {"facebook:4567", map[string]string{"name": ""}}, - {"facebook:ref:1337", map[string]string{}}} + {"facebook:ref:1337", map[string]string{}}, + } for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), testChannelsFBA[0], tc.urn) - assert.Equal(t, metadata, tc.metadata) + metadata, _ := handler.DescribeURN(context.Background(), channel, tc.urn, logger) + assert.Equal(t, metadata, tc.expectedMetadata) } } @@ -206,31 +211,40 @@ func TestDescribeIG(t *testing.T) { fbGraph := buildMockFBGraphIG(testCasesIG) defer fbGraph.Close() + channel := testChannelsIG[0] handler := newHandler("IG", "Instagram", false).(courier.URNDescriber) + logger := courier.NewChannelLoggerForReceive(channel) + tcs := []struct { - urn urns.URN - metadata map[string]string - }{{"instagram:1337", map[string]string{"name": "John Doe"}}, - {"instagram:4567", map[string]string{"name": ""}}} + urn urns.URN + expectedMetadata map[string]string + }{ + {"instagram:1337", map[string]string{"name": "John Doe"}}, + {"instagram:4567", map[string]string{"name": ""}}, + } for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), testChannelsIG[0], tc.urn) - assert.Equal(t, metadata, tc.metadata) + metadata, _ := handler.DescribeURN(context.Background(), channel, tc.urn, logger) + assert.Equal(t, metadata, tc.expectedMetadata) } } func TestDescribeWAC(t *testing.T) { + channel := testChannelsWAC[0] handler := newHandler("WAC", "Cloud API WhatsApp", false).(courier.URNDescriber) + logger := courier.NewChannelLoggerForReceive(channel) tcs := []struct { - urn urns.URN - metadata map[string]string - }{{"whatsapp:1337", map[string]string{}}, - {"whatsapp:4567", map[string]string{}}} + urn urns.URN + expectedMetadata map[string]string + }{ + {"whatsapp:1337", map[string]string{}}, + {"whatsapp:4567", map[string]string{}}, + } for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), testChannelsWAC[0], tc.urn) - assert.Equal(t, metadata, tc.metadata) + metadata, _ := handler.DescribeURN(context.Background(), testChannelsWAC[0], tc.urn, logger) + assert.Equal(t, metadata, tc.expectedMetadata) } } diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 085dc56c7..bb98463b4 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -6,6 +6,7 @@ import ( "crypto/sha1" "encoding/hex" "encoding/json" + "errors" "fmt" "net/http" "net/url" @@ -275,7 +276,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } // DescribeURN handles Jiochat contact details -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, logger *courier.ChannelLogger) (map[string]string, error) { accessToken, err := h.getAccessToken(channel) if err != nil { return nil, err @@ -293,11 +294,12 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn req, _ := http.NewRequest(http.MethodGet, reqURL.String(), nil) req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken)) - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - return nil, fmt.Errorf("unable to look up contact data: %s", err) + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return nil, errors.New("unable to look up contact data") } - nickname, _ := jsonparser.GetString(trace.ResponseBody, "nickname") + + nickname, _ := jsonparser.GetString(respBody, "nickname") return map[string]string{"name": nickname}, nil } diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index 6674ec2cb..50fab075d 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -255,7 +255,7 @@ func newServer(backend courier.Backend) courier.Server { return courier.NewServerWithLogger(config, backend, logger) } -func TestDescribe(t *testing.T) { +func TestDescribeURN(t *testing.T) { JCAPI := buildMockJCAPI(testCases) defer JCAPI.Close() @@ -272,18 +272,19 @@ func TestDescribe(t *testing.T) { s := newServer(mb) handler := &handler{handlers.NewBaseHandler(courier.ChannelType("JC"), "Jiochat")} handler.Initialize(s) + logger := courier.NewChannelLoggerForReceive(testChannels[0]) tcs := []struct { - urn urns.URN - metadata map[string]string + urn urns.URN + expectedMetadata map[string]string }{ {"jiochat:1337", map[string]string{"name": "John Doe"}}, {"jiochat:4567", map[string]string{"name": ""}}, } for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), testChannels[0], tc.urn) - assert.Equal(t, metadata, tc.metadata) + metadata, _ := handler.DescribeURN(context.Background(), testChannels[0], tc.urn, logger) + assert.Equal(t, metadata, tc.expectedMetadata) } } diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index 73b3de513..207f498eb 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -296,7 +296,7 @@ func sendFilePart(msg courier.Msg, token string, fileParams *FileParams) (*couri } // DescribeURN handles Slack user details -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, logger *courier.ChannelLogger) (map[string]string, error) { resource := "/users.info" urlStr := apiURL + resource @@ -309,13 +309,13 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn q.Add("user", urn.Path()) req.URL.RawQuery = q.Encode() - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - return nil, fmt.Errorf("request user info error: %s", err) + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return nil, errors.New("unable to look up user info") } var uInfo *UserInfo - if err := json.Unmarshal(trace.ResponseBody, &uInfo); err != nil { + if err := json.Unmarshal(respBody, &uInfo); err != nil { return nil, fmt.Errorf("unmarshal user info error:%s", err) } diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 1c2fd05cf..88b37d58d 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -354,16 +354,17 @@ func mockAttachmentURLs(fileServer *httptest.Server, testCases []ChannelSendTest return casesWithMockedUrls } -func TestDescribe(t *testing.T) { +func TestDescribeURN(t *testing.T) { server := buildMockSlackService([]ChannelHandleTestCase{}) defer server.Close() handler := newHandler().(courier.URNDescriber) + logger := courier.NewChannelLoggerForReceive(testChannels[0]) urn, _ := urns.NewURNFromParts(urns.SlackScheme, "U012345", "", "") data := map[string]string{"name": "dummy user"} - describe, err := handler.DescribeURN(context.Background(), testChannels[0], urn) + describe, err := handler.DescribeURN(context.Background(), testChannels[0], urn, logger) assert.Nil(t, err) assert.Equal(t, data, describe) } diff --git a/handlers/vk/vk.go b/handlers/vk/vk.go index 6745e1b6f..a10cc9e52 100644 --- a/handlers/vk/vk.go +++ b/handlers/vk/vk.go @@ -273,21 +273,21 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // DescribeURN handles VK contact details -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, logger *courier.ChannelLogger) (map[string]string, error) { req, err := http.NewRequest(http.MethodPost, apiBaseURL+actionGetUser, nil) - if err != nil { return nil, err } + params := buildApiBaseParams(channel) _, urnPath, _, _ := urn.ToParts() params.Set(paramUserIds, urnPath) req.URL.RawQuery = params.Encode() - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - return nil, err + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return nil, errors.New("unable to look up user info") } // parsing response @@ -295,7 +295,7 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn Users []userPayload `json:"response" validate:"required"` } payload := &responsePayload{} - err = json.Unmarshal(trace.ResponseBody, payload) + err = json.Unmarshal(respBody, payload) if err != nil { return nil, err diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index 8128db894..47ed21218 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -362,20 +362,18 @@ func buildMockVKService(testCases []ChannelHandleTestCase) *httptest.Server { return server } -func TestDescribe(t *testing.T) { +func TestDescribeURN(t *testing.T) { server := buildMockVKService([]ChannelHandleTestCase{}) defer server.Close() handler := newHandler().(courier.URNDescriber) - urn, _ := - urns.NewURNFromParts(urns.VKScheme, "123456789", "", "") + logger := courier.NewChannelLoggerForReceive(testChannels[0]) + urn, _ := urns.NewURNFromParts(urns.VKScheme, "123456789", "", "") data := map[string]string{"name": "John Doe"} - describe, err := handler.DescribeURN(context.Background(), testChannels[0], - urn) + describe, err := handler.DescribeURN(context.Background(), testChannels[0], urn, logger) assert.Nil(t, err) - assert.Equal(t, - data, describe) + assert.Equal(t, data, describe) } // setSendURL takes care of setting the send_url to our test server host diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index dafcb8ae1..e02bf1888 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -6,6 +6,7 @@ import ( "crypto/sha1" "encoding/hex" "encoding/json" + "errors" "fmt" "net/http" "net/url" @@ -268,15 +269,11 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - - if err != nil { - return status, err + resp, _, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return status, nil } + status.SetStatus(courier.MsgWired) } @@ -284,7 +281,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } // DescribeURN handles WeChat contact details -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, logger *courier.ChannelLogger) (map[string]string, error) { accessToken, err := h.getAccessToken(channel) if err != nil { return nil, err @@ -302,11 +299,12 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn req, _ := http.NewRequest(http.MethodGet, reqURL.String(), nil) - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - return nil, fmt.Errorf("unable to look up contact data: %s", err) + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return nil, errors.New("unable to look up contact data") } - nickname, err := jsonparser.GetString(trace.ResponseBody, "nickname") + + nickname, err := jsonparser.GetString(respBody, "nickname") if err != nil { return nil, err } diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index ea91d2a94..d83f52a89 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -101,7 +101,7 @@ func addValidSignature(r *http.Request) { nonce := "nonce" stringSlice := []string{"secret", timestamp, nonce} - sort.Sort(sort.StringSlice(stringSlice)) + sort.Strings(stringSlice) value := strings.Join(stringSlice, "") @@ -125,7 +125,7 @@ func addInvalidSignature(r *http.Request) { nonce := "nonce" stringSlice := []string{"secret", timestamp, nonce} - sort.Sort(sort.StringSlice(stringSlice)) + sort.Strings(stringSlice) value := strings.Join(stringSlice, "") @@ -268,18 +268,19 @@ func TestDescribe(t *testing.T) { s := newServer(mb) handler := &handler{handlers.NewBaseHandler(courier.ChannelType("WC"), "WeChat")} handler.Initialize(s) + logger := courier.NewChannelLoggerForReceive(testChannels[0]) tcs := []struct { - urn urns.URN - metadata map[string]string + urn urns.URN + expectedMetadata map[string]string }{ {"wechat:abcdeKNOWN_OPEN_ID", map[string]string{"name": "John Doe"}}, {"wechat:foo__NOT__KNOWN", map[string]string{"name": ""}}, } for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), testChannels[0], tc.urn) - assert.Equal(t, metadata, tc.metadata) + metadata, _ := handler.DescribeURN(context.Background(), testChannels[0], tc.urn, logger) + assert.Equal(t, metadata, tc.expectedMetadata) } } @@ -318,50 +319,57 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", + { + Label: "Plain Send", MsgText: "Simple Message ☺", MsgURN: "wechat:12345", - ExpectedStatus: "W", - ExpectedExternalID: "", MockResponseStatus: 200, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"Simple Message ☺"}}`, - SendPrep: setSendURL}, - {Label: "Long Send", + ExpectedStatus: "W", + ExpectedExternalID: "", + SendPrep: setSendURL, + }, + { + Label: "Long Send", MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", MsgURN: "wechat:12345", - ExpectedStatus: "W", - ExpectedExternalID: "", MockResponseStatus: 200, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"I need to keep adding more things to make it work"}}`, - SendPrep: setSendURL}, - {Label: "Send Attachment", + ExpectedStatus: "W", + ExpectedExternalID: "", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", MsgText: "My pic!", MsgURN: "wechat:12345", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - ExpectedExternalID: "", MockResponseStatus: 200, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }, ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"My pic!\nhttps://foo.bar/image.jpg"}}`, - SendPrep: setSendURL}, - {Label: "Error Sending", + ExpectedStatus: "W", + ExpectedExternalID: "", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", MsgText: "Error Message", MsgURN: "wechat:12345", - ExpectedStatus: "E", MockResponseStatus: 401, - ExpectedErrors: []string{"received non 200 status: 401"}, - SendPrep: setSendURL}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } func setupBackend(mb *test.MockBackend) { From 9c5291c586509a1d89d902bf56abc62aa855c939 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Fri, 12 Aug 2022 17:34:13 +0200 Subject: [PATCH 066/294] Support media attachments for LINE --- handlers/line/line.go | 46 +++++++++++++++++++++++++++------ handlers/line/line_test.go | 52 ++++++++++++++++++++++++++++++++++---- 2 files changed, 85 insertions(+), 13 deletions(-) diff --git a/handlers/line/line.go b/handlers/line/line.go index f7710743c..1e8dc0994 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -11,10 +11,10 @@ import ( "io/ioutil" "net/http" "net/url" - "strings" "time" "github.com/buger/jsonparser" + "github.com/pkg/errors" "github.com/nyaruka/gocommon/urns" @@ -32,6 +32,14 @@ var ( signatureHeader = "X-Line-Signature" ) +// see https://core.telegram.org/bots/api#sending-files +var mediaSupport = map[handlers.MediaType]handlers.MediaTypeSupport{ + handlers.MediaTypeImage: {Types: []string{"image/jpe", "image/jpg", "image/jpeg", "image/png"}, MaxBytes: 10 * 1024 * 1024}, + handlers.MediaTypeAudio: {Types: []string{"audio/mp4", "audio/m4a"}, MaxBytes: 200 * 1024 * 1024}, + handlers.MediaTypeVideo: {Types: []string{"video/mp4"}, MaxBytes: 200 * 1024 * 1024}, + handlers.MediaTypeApplication: {}, +} + func init() { courier.RegisterHandler(newHandler()) } @@ -258,6 +266,18 @@ type mtImageMsg struct { PreviewURL string `json:"previewImageUrl"` } +type mtVideoMsg struct { + Type string `json:"type"` + URL string `json:"originalContentUrl"` + PreviewURL string `json:"previewImageUrl"` +} + +type mtAudioMsg struct { + Type string `json:"type"` + URL string `json:"originalContentUrl"` + Duration int `json:"duration"` +} + type mtPayload struct { To string `json:"to,omitempty"` ReplyToken string `json:"replyToken,omitempty"` @@ -300,19 +320,29 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } } } + + attachments, err := handlers.ResolveAttachments(ctx, h.Backend(), msg.Attachments(), mediaSupport, true) + if err != nil { + return nil, errors.Wrap(err, "error resolving attachments") + } + // fill all msg parts with attachment parts - for _, attachment := range msg.Attachments() { + for _, attachment := range attachments { + var jsonMsg []byte var err error - prefix, url := handlers.SplitAttachment(attachment) - - switch mediaType := strings.Split(prefix, "/")[0]; mediaType { - case "image": - jsonMsg, err = json.Marshal(mtImageMsg{Type: "image", URL: url, PreviewURL: url}) + switch attachment.Type { + case handlers.MediaTypeImage: + jsonMsg, err = json.Marshal(mtImageMsg{Type: "image", URL: attachment.Media.URL(), PreviewURL: attachment.Media.URL()}) + case handlers.MediaTypeVideo: + jsonMsg, err = json.Marshal(mtVideoMsg{Type: "video", URL: attachment.Media.URL(), PreviewURL: attachment.Thumbnail.URL()}) + case handlers.MediaTypeAudio: + jsonMsg, err = json.Marshal(mtAudioMsg{Type: "audio", URL: attachment.Media.URL(), Duration: attachment.Media.Duration()}) default: - jsonMsg, err = json.Marshal(mtTextMsg{Type: "text", Text: url}) + jsonMsg, err = json.Marshal(mtTextMsg{Type: "text", Text: attachment.URL}) } + if err == nil { jsonMsgs = append(jsonMsgs, string(jsonMsg)) } diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index f0076f193..293d16ce3 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -360,8 +360,31 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say,"},{"type":"text","text":"I need to keep adding more things to make it work"}]}`, SendPrep: setSendURL}, + {Label: "Send Audio Attachment", + MsgText: "My Audio!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"audio/mp3:http://mock.com/3456/test.mp3"}, + ExpectedStatus: "W", + MockResponseBody: `{}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "Bearer AccessToken", + }, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My Audio!"},{"type":"audio","originalContentUrl":"http://mock.com/2345/test.m4a","duration":200}]}`, + SendPrep: setSendURL}, + {Label: "Send Video Attachment", + MsgText: "My Video!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"video/mp4:http://mock.com/5678/test.mp4"}, + ExpectedStatus: "W", + MockResponseBody: `{}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "Bearer AccessToken", + }, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My Video!"},{"type":"video","originalContentUrl":"http://mock.com/5678/test.mp4","previewImageUrl":"http://mock.com/4567/test.jpg"}]}`, + SendPrep: setSendURL}, + {Label: "Send Image Attachment", - MsgText: "My pic!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MsgText: "My pic!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, ExpectedStatus: "W", MockResponseBody: `{}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -369,10 +392,10 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Accept": "application/json", "Authorization": "Bearer AccessToken", }, - ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My pic!"},{"type":"image","originalContentUrl":"https://foo.bar/image.jpg","previewImageUrl":"https://foo.bar/image.jpg"}]}`, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My pic!"},{"type":"image","originalContentUrl":"http://mock.com/1234/test.jpg","previewImageUrl":"http://mock.com/1234/test.jpg"}]}`, SendPrep: setSendURL}, {Label: "Send Other Attachment", - MsgText: "My video!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, + MsgText: "My doc!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, ExpectedStatus: "W", MockResponseBody: `{}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -380,7 +403,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Accept": "application/json", "Authorization": "Bearer AccessToken", }, - ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My video!"},{"type":"text","text":"https://foo.bar/video.mp4"}]}`, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My doc!"},{"type":"text","text":"https://foo.bar/document.pdf"}]}`, SendPrep: setSendURL}, {Label: "Send Message Batches", MsgText: tooLongMsg, @@ -447,7 +470,26 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL}, } +// setSendURL takes care of setting the base_url to our test server host +func setupMedia(mb *test.MockBackend) { + imageJPG := test.NewMockMedia("test.jpg", "image/jpeg", "http://mock.com/1234/test.jpg", 1024*1024, 640, 480, 0, nil) + + audioM4A := test.NewMockMedia("test.m4a", "audio/mp4", "http://mock.com/2345/test.m4a", 1024*1024, 0, 0, 200, nil) + audioMP3 := test.NewMockMedia("test.mp3", "audio/mp3", "http://mock.com/3456/test.mp3", 1024*1024, 0, 0, 200, []courier.Media{audioM4A}) + + thumbJPG := test.NewMockMedia("test.jpg", "image/jpeg", "http://mock.com/4567/test.jpg", 1024*1024, 640, 480, 0, nil) + videoMP4 := test.NewMockMedia("test.mp4", "video/mp4", "http://mock.com/5678/test.mp4", 1024*1024, 0, 0, 1000, []courier.Media{thumbJPG}) + + videoMOV := test.NewMockMedia("test.mov", "video/quicktime", "http://mock.com/6789/test.mov", 100*1024*1024, 0, 0, 2000, nil) + + mb.MockMedia(imageJPG) + mb.MockMedia(audioMP3) + mb.MockMedia(videoMP4) + mb.MockMedia(videoMOV) +} + func TestSending(t *testing.T) { + maxMsgLength = 160 var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "LN", "2020", "US", map[string]interface{}{ @@ -455,7 +497,7 @@ func TestSending(t *testing.T) { }, ) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, setupMedia) } func TestBuildMediaRequest(t *testing.T) { From ae22163b110622809c5b1716b26819107e0940e8 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 12 Aug 2022 12:44:22 -0500 Subject: [PATCH 067/294] Update to latest gocommon and fix some go warnings --- channel_log_test.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- handler_test.go | 6 +++--- handlers/http_test.go | 4 ++-- log.go | 2 +- responses.go | 2 -- sender.go | 10 +++++----- server.go | 8 +++++--- spool.go | 3 ++- 10 files changed, 22 insertions(+), 21 deletions(-) diff --git a/channel_log_test.go b/channel_log_test.go index 01420271d..a3b58fd94 100644 --- a/channel_log_test.go +++ b/channel_log_test.go @@ -11,7 +11,7 @@ import ( ) func TestNewChannelLogFromTrace(t *testing.T) { - httpx.SetRequestor(httpx.NewMockRequestor(map[string][]httpx.MockResponse{ + httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ "https://api.messages.com/send.json": { httpx.NewMockResponse(200, nil, []byte(`{"status":"success"}`)), httpx.MockConnectionError, diff --git a/go.mod b/go.mod index 690b540e0..ec33152ae 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.6 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.25.0 + github.com/nyaruka/gocommon v1.26.0 github.com/nyaruka/null v1.2.0 github.com/nyaruka/redisx v0.2.2 github.com/patrickmn/go-cache v2.1.0+incompatible diff --git a/go.sum b/go.sum index 8afc61e4b..9ea11db60 100644 --- a/go.sum +++ b/go.sum @@ -76,8 +76,8 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.25.0 h1:/wi16Q9qUF3NOnRgM5q/c55dRtX0xLDHu7hDU0OTeWg= -github.com/nyaruka/gocommon v1.25.0/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= +github.com/nyaruka/gocommon v1.26.0 h1:rpi2nhjXRTP7oMfG0P/pOJQH2nQBAHL/ygw/HYF6fxA= +github.com/nyaruka/gocommon v1.26.0/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= diff --git a/handler_test.go b/handler_test.go index 43cd454c9..b28aa62d8 100644 --- a/handler_test.go +++ b/handler_test.go @@ -3,7 +3,7 @@ package courier_test import ( "context" "errors" - "io/ioutil" + "io" "net/http" "testing" "time" @@ -133,7 +133,7 @@ func TestHandling(t *testing.T) { assert.NoError(err) assert.Equal(400, resp.StatusCode) defer resp.Body.Close() - body, _ := ioutil.ReadAll(resp.Body) + body, _ := io.ReadAll(resp.Body) assert.Contains(string(body), "missing from or text") req, _ := http.NewRequest("GET", "http://localhost:8080/c/dm/e4bb1578-29da-4fa5-a214-9da19dd24230/receive?from=2065551212&text=hello", nil) @@ -142,7 +142,7 @@ func TestHandling(t *testing.T) { assert.NoError(err) assert.Equal(200, resp.StatusCode) defer resp.Body.Close() - body, _ = ioutil.ReadAll(resp.Body) + body, _ = io.ReadAll(resp.Body) assert.Contains(string(body), "ok") // cookie stripped diff --git a/handlers/http_test.go b/handlers/http_test.go index 64ab44ccc..ff5e7ca7a 100644 --- a/handlers/http_test.go +++ b/handlers/http_test.go @@ -13,7 +13,7 @@ import ( ) func TestDoHTTPRequest(t *testing.T) { - httpx.SetRequestor(httpx.NewMockRequestor(map[string][]httpx.MockResponse{ + httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ "https://api.messages.com/send.json": { httpx.NewMockResponse(200, nil, []byte(`{"status":"success"}`)), httpx.NewMockResponse(400, nil, []byte(`{"status":"error"}`)), @@ -53,7 +53,7 @@ func TestDoHTTPRequest(t *testing.T) { } func TestMakeHTTPRequest(t *testing.T) { - httpx.SetRequestor(httpx.NewMockRequestor(map[string][]httpx.MockResponse{ + httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ "https://api.messages.com/send.json": { httpx.NewMockResponse(200, nil, []byte(`{"status":"success"}`)), httpx.NewMockResponse(400, nil, []byte(`{"status":"error"}`)), diff --git a/log.go b/log.go index 10578a06f..773ec78fe 100644 --- a/log.go +++ b/log.go @@ -91,5 +91,5 @@ func getElapsedMS(r *http.Request) float64 { if !isTime { return -1 } - return float64(time.Now().Sub(startTime)) / float64(time.Millisecond) + return float64(time.Since(startTime)) / float64(time.Millisecond) } diff --git a/responses.go b/responses.go index 6ad634058..90e10d946 100644 --- a/responses.go +++ b/responses.go @@ -12,8 +12,6 @@ import ( validator "gopkg.in/go-playground/validator.v9" ) -const statusMsgNotFoundDetail = "message not found, ignored" - // writeAndLogRequestError writes a JSON response for the passed in message and logs an info messages func writeAndLogRequestError(ctx context.Context, w http.ResponseWriter, r *http.Request, c Channel, err error) error { LogRequestError(r, c, err) diff --git a/sender.go b/sender.go index 37949ccf0..6473a949b 100644 --- a/sender.go +++ b/sender.go @@ -65,7 +65,7 @@ func (f *Foreman) Assign() { backend := f.server.Backend() lastSleep := false - for true { + for { select { // return if we have been told to stop case <-f.quit: @@ -106,7 +106,6 @@ type Sender struct { id int foreman *Foreman job chan Msg - log *logrus.Entry } // NewSender creates a new sender responsible for sending messages @@ -121,14 +120,15 @@ func NewSender(foreman *Foreman, id int) *Sender { // Start starts our Sender's goroutine and has it start waiting for tasks from the foreman func (w *Sender) Start() { + w.foreman.server.WaitGroup().Add(1) + go func() { - w.foreman.server.WaitGroup().Add(1) defer w.foreman.server.WaitGroup().Done() log := logrus.WithField("comp", "sender").WithField("sender_id", w.id) log.Debug("started") - for true { + for { // list ourselves as available for work w.foreman.availableSenders <- w @@ -198,7 +198,7 @@ func (w *Sender) sendMessage(msg Msg) { } else { // send our message status, err = server.SendMsg(sendCTX, msg, logger) - duration := time.Now().Sub(start) + duration := time.Since(start) secondDuration := float64(duration) / float64(time.Second) // handlers can currently return logs either via the logger or on the status object diff --git a/server.go b/server.go index 55aa1e8b3..09a93f3e7 100644 --- a/server.go +++ b/server.go @@ -121,9 +121,10 @@ func (s *server) Start() error { WriteTimeout: 30 * time.Second, } + s.waitGroup.Add(1) + // and start serving HTTP go func() { - s.waitGroup.Add(1) defer s.waitGroup.Done() err := s.httpServer.ListenAndServe() if err != nil && err != http.ErrServerClosed { @@ -135,9 +136,10 @@ func (s *server) Start() error { } }() + s.waitGroup.Add(1) + // start our heartbeat go func() { - s.waitGroup.Add(1) defer s.waitGroup.Done() for !s.stopped { @@ -309,7 +311,7 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe }() events, err := handlerFunc(ctx, channel, ww, r) - duration := time.Now().Sub(start) + duration := time.Since(start) secondDuration := float64(duration) / float64(time.Second) // if we received an error, write it out and report it diff --git a/spool.go b/spool.go index 9f010492a..edacc9da6 100644 --- a/spool.go +++ b/spool.go @@ -42,8 +42,9 @@ func startSpoolFlushers(s Server) { flushers[i] = newSpoolFlusher(s, reg.directory, reg.flusher) } + s.WaitGroup().Add(1) + go func() { - s.WaitGroup().Add(1) defer s.WaitGroup().Done() log := logrus.WithField("comp", "spool") From 00918215c8fffb31d108ecca1e674735d97d287e Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 12 Aug 2022 13:48:03 -0500 Subject: [PATCH 068/294] Replace handlers.MockedResponse with httpx.MockResponse --- handlers/facebookapp/facebookapp_test.go | 73 +++------ handlers/kaleyra/kaleyra_test.go | 33 ++-- handlers/line/line_test.go | 17 +- handlers/slack/slack_test.go | 15 +- handlers/test.go | 11 +- handlers/twitter/twitter_test.go | 122 +++------------ handlers/vk/vk_test.go | 65 +++----- handlers/whatsapp/whatsapp_test.go | 190 ++++++----------------- 8 files changed, 136 insertions(+), 390 deletions(-) diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 23bcfd798..52cdc94c7 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -14,6 +14,7 @@ import ( "github.com/nyaruka/courier/handlers" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/urns" "github.com/stretchr/testify/assert" ) @@ -631,23 +632,17 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MsgText: "audio caption", MsgURN: "whatsapp:250788123123", MsgAttachments: []string{"audio/mpeg:https://foo.bar/audio.mp3"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"audio","audio":{"link":"https://foo.bar/audio.mp3"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"audio caption","preview_url":false}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -658,23 +653,17 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MsgText: "document caption", MsgURN: "whatsapp:250788123123", MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"document","document":{"link":"https://foo.bar/document.pdf"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"document caption","preview_url":false}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -685,23 +674,17 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MsgText: "document caption", MsgURN: "whatsapp:250788123123", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"document caption","preview_url":false}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -712,23 +695,17 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MsgText: "video caption", MsgURN: "whatsapp:250788123123", MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"video","video":{"link":"https://foo.bar/video.mp4"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"video caption","preview_url":false}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -795,23 +772,17 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MsgURN: "whatsapp:250788123123", MsgQuickReplies: []string{"BUTTON1"}, MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -823,23 +794,17 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MsgURN: "whatsapp:250788123123", MsgQuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4"}, MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), { Method: "POST", Path: "/12345_ID/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", diff --git a/handlers/kaleyra/kaleyra_test.go b/handlers/kaleyra/kaleyra_test.go index 6f51a8657..23451738d 100644 --- a/handlers/kaleyra/kaleyra_test.go +++ b/handlers/kaleyra/kaleyra_test.go @@ -9,6 +9,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) const ( @@ -175,23 +176,17 @@ var sendTestCases = []ChannelSendTestCase{ MsgURN: "whatsapp:14133881111", ExpectedStatus: "W", ExpectedExternalID: "f75fbe1e-a0c0-4923-96e8-5043aa617b2b:0", - MockResponses: map[MockedRequest]MockedResponse{ - MockedRequest{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ + { Method: "POST", Path: "/v1/SID/messages", BodyContains: "image bytes", - }: { - Status: 200, - Body: `{"id":"58f86fab-85c5-4f7c-9b68-9c323248afc4:0"}`, - }, - MockedRequest{ + }: httpx.NewMockResponse(200, nil, []byte(`{"id":"58f86fab-85c5-4f7c-9b68-9c323248afc4:0"}`)), + { Method: "POST", Path: "/v1/SID/messages", BodyContains: "video bytes", - }: { - Status: 200, - Body: `{"id":"f75fbe1e-a0c0-4923-96e8-5043aa617b2b:0"}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"id":"f75fbe1e-a0c0-4923-96e8-5043aa617b2b:0"}`)), }, SendPrep: setSendURL, }, @@ -201,23 +196,17 @@ var sendTestCases = []ChannelSendTestCase{ MsgAttachments: []string{"image/jpg:https://foo.bar/image.jpg", "image/png:https://foo.bar/video.wmv"}, MsgURN: "whatsapp:14133881111", ExpectedStatus: "F", - MockResponses: map[MockedRequest]MockedResponse{ - MockedRequest{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ + { Method: "POST", Path: "/v1/SID/messages", BodyContains: "image bytes", - }: { - Status: 200, - Body: `{"id":"58f86fab-85c5-4f7c-9b68-9c323248afc4:0"}`, - }, - MockedRequest{ + }: httpx.NewMockResponse(200, nil, []byte(`{"id":"58f86fab-85c5-4f7c-9b68-9c323248afc4:0"}`)), + { Method: "POST", Path: "/v1/SID/messages", BodyContains: "video bytes", - }: { - Status: 400, - Body: `{"error":{"media":"invalid media type"}}`, - }, + }: httpx.NewMockResponse(400, nil, []byte(`{"error":{"media":"invalid media type"}}`)), }, SendPrep: setSendURL, }, diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index f0076f193..33e348a17 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -10,6 +10,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" "github.com/stretchr/testify/assert" ) @@ -420,23 +421,17 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Send Push Message If Invalid Reply", MsgText: "Simple Message", MsgURN: "line:uabcdefghij", MsgResponseToExternalID: "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA", ExpectedStatus: "W", - MockResponses: map[MockedRequest]MockedResponse{ - MockedRequest{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ + { Method: "POST", Path: "/v2/bot/message/reply", BodyContains: `{"replyToken":"nHuyWiB7yP5Zw52FIkcQobQuGDXCTA","messages":[{"type":"text","text":"Simple Message"}]}`, - }: { - Status: 400, - Body: `{"message":"Invalid reply token"}`, - }, - MockedRequest{ + }: httpx.NewMockResponse(400, nil, []byte(`{"message":"Invalid reply token"}`)), + { Method: "POST", Path: "/v2/bot/message/push", BodyContains: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Simple Message"}]}`, - }: { - Status: 200, - Body: `{}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{}`)), }, SendPrep: setSendURL}, {Label: "Error Sending", diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 1c2fd05cf..d0498ac85 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -14,6 +14,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/urns" "github.com/stretchr/testify/assert" ) @@ -212,15 +213,12 @@ var fileSendTestCases = []ChannelSendTestCase{ MsgText: "", MsgURN: "slack:U0123ABCDEF", ExpectedStatus: "W", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.png"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/files.upload", BodyContains: "image.png", - }: { - Status: 200, - Body: `{"ok":true,"file":{"id":"F1L3SL4CK1D"}}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"ok":true,"file":{"id":"F1L3SL4CK1D"}}`)), }, SendPrep: setSendUrl, }, @@ -229,15 +227,12 @@ var fileSendTestCases = []ChannelSendTestCase{ MsgText: "", MsgURN: "slack:U0123ABCDEF", ExpectedStatus: "W", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.png"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/files.upload", BodyContains: "image.png", - }: { - Status: 200, - Body: `{"ok":true,"file":{"id":"F1L3SL4CK1D"}}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"ok":true,"file":{"id":"F1L3SL4CK1D"}}`)), }, SendPrep: setSendUrl, }, diff --git a/handlers/test.go b/handlers/test.go index d04f3d9e4..e3183e88e 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -17,6 +17,7 @@ import ( _ "github.com/lib/pq" // postgres driver "github.com/nyaruka/courier" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/urns" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" @@ -69,12 +70,6 @@ type MockedRequest struct { BodyContains string } -// MockedResponse is a fake HTTP response -type MockedResponse struct { - Status int - Body string -} - // ChannelSendTestCase defines the test values for a particular test case type ChannelSendTestCase struct { Label string @@ -93,7 +88,7 @@ type ChannelSendTestCase struct { MockResponseStatus int MockResponseBody string - MockResponses map[MockedRequest]MockedResponse + MockResponses map[MockedRequest]*httpx.MockResponse ExpectedRequestPath string ExpectedURLParams map[string]string @@ -250,7 +245,7 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour bodyStr := string(body)[:] if mockRequest.Method == r.Method && mockRequest.Path == r.URL.Path && mockRequest.RawQuery == r.URL.RawQuery && (mockRequest.Body == bodyStr || (mockRequest.BodyContains != "" && strings.Contains(bodyStr, mockRequest.BodyContains))) { w.WriteHeader(mockResponse.Status) - w.Write([]byte(mockResponse.Body)) + w.Write(mockResponse.Body) mockRRCount++ break } diff --git a/handlers/twitter/twitter_test.go b/handlers/twitter/twitter_test.go index c093a6a43..5bf1b3242 100644 --- a/handlers/twitter/twitter_test.go +++ b/handlers/twitter/twitter_test.go @@ -12,6 +12,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) var testChannels = []courier.Channel{ @@ -223,56 +224,32 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "document caption", MsgURN: "twitterid:12345", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/1.1/media/upload.json", Body: `command=INIT&media_category=dm_image&media_type=image%2Fjpeg&total_bytes=10`, - }: { - Status: 200, - Body: `{ - "media_id": 710511363345354753, - "media_id_string": "710511363345354753", - }`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"media_id": 710511363345354753, "media_id_string": "710511363345354753"}`)), { Method: "POST", Path: "/1.1/media/upload.json", BodyContains: "APPEND", - }: { - Status: 200, - Body: `{ - "media_id": 710511363345354753, - "media_id_string": "710511363345354753", - }`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"media_id": 710511363345354753, "media_id_string": "710511363345354753"}`)), { Method: "POST", Path: "/1.1/media/upload.json", Body: `command=FINALIZE&media_id=710511363345354753`, - }: { - Status: 200, - Body: `{ - "media_id": 710511363345354753, - "media_id_string": "710511363345354753", - }`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"media_id": 710511363345354753, "media_id_string": "710511363345354753"}`)), { Method: "POST", Path: "/1.1/direct_messages/events/new.json", Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"document caption"}}}}`, - }: { - Status: 200, - Body: `{"event": { "id": "133"}}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"event": { "id": "133"}}`)), { Method: "POST", Path: "/1.1/direct_messages/events/new.json", Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"","attachment":{"type":"media","media":{"id":"710511363345354753"}}}}}}`, - }: { - Status: 200, - Body: `{"event": { "id": "133"}}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"event": { "id": "133"}}`)), }, ExpectedStatus: "W", ExpectedExternalID: "133", @@ -283,56 +260,32 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "document caption", MsgURN: "twitterid:12345", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/1.1/media/upload.json", Body: `command=INIT&media_category=dm_image&media_type=image%2Fjpeg&total_bytes=10`, - }: { - Status: 200, - Body: `{ - "media_id": 710511363345354753, - "media_id_string": "710511363345354753", - }`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"media_id": 710511363345354753, "media_id_string": "710511363345354753"}`)), { Method: "POST", Path: "/1.1/media/upload.json", BodyContains: "APPEND", - }: { - Status: 200, - Body: `{ - "media_id": 710511363345354753, - "media_id_string": "710511363345354753", - }`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"media_id": 710511363345354753, "media_id_string": "710511363345354753"}`)), { Method: "POST", Path: "/1.1/media/upload.json", Body: `command=FINALIZE&media_id=710511363345354753`, - }: { - Status: 200, - Body: `{ - "media_id": 710511363345354753, - "media_id_string": "710511363345354753", - }`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"media_id": 710511363345354753, "media_id_string": "710511363345354753"}`)), { Method: "POST", Path: "/1.1/direct_messages/events/new.json", Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"document caption"}}}}`, - }: { - Status: 200, - Body: `{"event": { "id": "133"}}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"event": { "id": "133"}}`)), { Method: "POST", Path: "/1.1/direct_messages/events/new.json", Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"","attachment":{"type":"media","media":{"id":"710511363345354753"}}}}}}`, - }: { - Status: 200, - Body: `{"event": { "id": "133"}}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"event": { "id": "133"}}`)), }, ExpectedStatus: "W", ExpectedExternalID: "133", @@ -343,57 +296,32 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "document caption", MsgURN: "twitterid:12345", MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/1.1/media/upload.json", Body: `command=INIT&media_category=dm_video&media_type=video%2Fmp4&total_bytes=10`, - }: { - Status: 200, - Body: `{ - "media_id": 710511363345354753, - "media_id_string": "710511363345354753", - }`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"media_id": 710511363345354753, "media_id_string": "710511363345354753"}`)), { Method: "POST", Path: "/1.1/media/upload.json", BodyContains: "APPEND", - }: { - Status: 200, - Body: `{ - "media_id": 710511363345354753, - "media_id_string": "710511363345354753", - }`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"media_id": 710511363345354753, "media_id_string": "710511363345354753"}`)), { Method: "POST", Path: "/1.1/media/upload.json", Body: `command=FINALIZE&media_id=710511363345354753`, - }: { - Status: 200, - Body: `{ - "media_id": 710511363345354753, - "media_id_string": "710511363345354753", - "processing_info" : {"state": "pending", "check_after_secs": 2}, - }`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"media_id": 710511363345354753, "media_id_string": "710511363345354753"}`)), { Method: "POST", Path: "/1.1/direct_messages/events/new.json", Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"document caption"}}}}`, - }: { - Status: 200, - Body: `{"event": { "id": "133"}}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"event": { "id": "133"}}`)), { Method: "POST", Path: "/1.1/direct_messages/events/new.json", Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"","attachment":{"type":"media","media":{"id":"710511363345354753"}}}}}}`, - }: { - Status: 200, - Body: `{"event": { "id": "133"}}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"event": { "id": "133"}}`)), }, ExpectedStatus: "W", ExpectedExternalID: "133", @@ -404,23 +332,17 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "My audio!", MsgURN: "twitterid:12345", MsgAttachments: []string{"audio/mp3:https://foo.bar/audio.mp3"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/1.1/direct_messages/events/new.json", Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"My audio!"}}}}`, - }: { - Status: 200, - Body: `{"event": { "id": "133"}}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"event": { "id": "133"}}`)), { Method: "POST", Path: "/1.1/direct_messages/events/new.json", BodyContains: `"text":"http`, // audio link send as text - }: { - Status: 200, - Body: `{"event": { "id": "133"}}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"event": { "id": "133"}}`)), }, ExpectedStatus: "W", ExpectedExternalID: "133", diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index 8128db894..431d198c8 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -9,6 +9,7 @@ import ( "testing" "time" + "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/urns" "github.com/stretchr/testify/assert" @@ -392,15 +393,12 @@ var sendTestCases = []ChannelSendTestCase{ ExpectedStatus: "S", SendPrep: setSendURL, ExpectedExternalID: "1", - MockResponses: map[MockedRequest]MockedResponse{ - MockedRequest{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ + { Method: "POST", Path: actionSendMessage, RawQuery: "access_token=token123xyz&attachment=&message=Simple+message&random_id=10&user_id=123456789&v=5.103", - }: { - Status: 200, - Body: `{"response": 1}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"response": 1}`)), }, }, { @@ -411,31 +409,22 @@ var sendTestCases = []ChannelSendTestCase{ ExpectedStatus: "S", SendPrep: setSendURL, ExpectedExternalID: "1", - MockResponses: map[MockedRequest]MockedResponse{ - MockedRequest{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ + { Method: "POST", Path: "/upload/photo", BodyContains: `media body`, - }: { - Status: 200, - Body: `{"server": 109876, "photo": "...", "hash": "zxc987qwe"}`, - }, - MockedRequest{ + }: httpx.NewMockResponse(200, nil, []byte(`{"server": 109876, "photo": "...", "hash": "zxc987qwe"}`)), + { Method: "POST", Path: actionSaveUploadedPhotoInfo, RawQuery: "access_token=token123xyz&hash=zxc987qwe&photo=...&server=109876&v=5.103", - }: { - Status: 200, - Body: `{"response": [{"id": 1, "owner_id": 1901234}]}`, - }, - MockedRequest{ + }: httpx.NewMockResponse(200, nil, []byte(`{"response": [{"id": 1, "owner_id": 1901234}]}`)), + { Method: "POST", Path: actionSendMessage, RawQuery: "access_token=token123xyz&attachment=photo1901234_1&message=&random_id=10&user_id=123456789&v=5.103", - }: { - Status: 200, - Body: `{"response": 1}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"response": 1}`)), }, }, { @@ -446,31 +435,22 @@ var sendTestCases = []ChannelSendTestCase{ ExpectedStatus: "S", SendPrep: setSendURL, ExpectedExternalID: "1", - MockResponses: map[MockedRequest]MockedResponse{ - MockedRequest{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ + { Method: "POST", Path: "/upload/photo", BodyContains: `media body`, - }: { - Status: 200, - Body: `{"server": 109876, "photo": "...", "hash": "zxc987qwe"}`, - }, - MockedRequest{ + }: httpx.NewMockResponse(200, nil, []byte(`{"server": 109876, "photo": "...", "hash": "zxc987qwe"}`)), + { Method: "POST", Path: actionSaveUploadedPhotoInfo, RawQuery: "access_token=token123xyz&hash=zxc987qwe&photo=...&server=109876&v=5.103", - }: { - Status: 200, - Body: `{"response": [{"id": 1, "owner_id": 1901234}]}`, - }, - MockedRequest{ + }: httpx.NewMockResponse(200, nil, []byte(`{"response": [{"id": 1, "owner_id": 1901234}]}`)), + { Method: "POST", Path: actionSendMessage, RawQuery: "access_token=token123xyz&attachment=photo1901234_1&message=Attachments" + url.QueryEscape("\n\nhttps://foo.bar/audio.mp3") + "&random_id=10&user_id=123456789&v=5.103", - }: { - Status: 200, - Body: `{"response": 1}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"response": 1}`)), }, }, { @@ -481,15 +461,12 @@ var sendTestCases = []ChannelSendTestCase{ ExpectedStatus: "S", SendPrep: setSendURL, ExpectedExternalID: "1", - MockResponses: map[MockedRequest]MockedResponse{ - MockedRequest{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ + { Method: "POST", Path: actionSendMessage, RawQuery: "access_token=token123xyz&attachment=&keyboard=" + url.QueryEscape(keyboardJson) + "&message=Send+keyboard&random_id=10&user_id=123456789&v=5.103", - }: { - Status: 200, - Body: `{"response": 1}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"response": 1}`)), }, }, } diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index 39b2f0c82..5602a1461 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -12,6 +12,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" "github.com/stretchr/testify/assert" ) @@ -451,23 +452,17 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "audio has no caption, sent as text", MsgURN: "whatsapp:250788123123", MsgAttachments: []string{"audio/mpeg:https://foo.bar/audio.mp3"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"audio","audio":{"link":"https://foo.bar/audio.mp3"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"text","text":{"body":"audio has no caption, sent as text"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -478,23 +473,17 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "audio has no caption, sent as text with a https://example.com", MsgURN: "whatsapp:250788123123", MsgAttachments: []string{"audio/mpeg:https://foo.bar/audio.mp3"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"audio","audio":{"link":"https://foo.bar/audio.mp3"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"text","preview_url":true,"text":{"body":"audio has no caption, sent as text with a https://example.com"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -505,15 +494,12 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "document caption", MsgURN: "whatsapp:250788123123", MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"document","document":{"link":"https://foo.bar/document.pdf","caption":"document caption","filename":"document.pdf"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -524,15 +510,12 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "document caption", MsgURN: "whatsapp:250788123123", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg","caption":"document caption"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -543,15 +526,12 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "video caption", MsgURN: "whatsapp:250788123123", MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"video","video":{"link":"https://foo.bar/video.mp4","caption":"video caption"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -604,23 +584,17 @@ var defaultSendTestCases = []ChannelSendTestCase{ Label: "WhatsApp Contact Error", MsgText: "contact status error", MsgURN: "whatsapp:250788123123", - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"text","text":{"body":"contact status error"}}`, - }: { - Status: 404, - Body: `{"errors": [{"code":1006,"title":"Resource not found","details":"unknown contact"}]}`, - }, + }: httpx.NewMockResponse(404, nil, []byte(`{"errors": [{"code":1006,"title":"Resource not found","details":"unknown contact"}]}`)), { Method: "POST", Path: "/v1/contacts", Body: `{"blocking":"wait","contacts":["+250788123123"],"force_check":true}`, - }: { - Status: 200, - Body: `{"contacts":[{"input":"+250788123123","status":"invalid"}]}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"contacts":[{"input":"+250788123123","status":"invalid"}]}`)), }, ExpectedStatus: "E", SendPrep: setSendURL, @@ -629,32 +603,23 @@ var defaultSendTestCases = []ChannelSendTestCase{ Label: "Try Messaging Again After WhatsApp Contact Check", MsgText: "try again", MsgURN: "whatsapp:250788123123", - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"text","text":{"body":"try again"}}`, - }: { - Status: 404, - Body: `{"errors": [{"code": 1006, "title": "Resource not found", "details": "unknown contact"}]}`, - }, + }: httpx.NewMockResponse(404, nil, []byte(`{"errors": [{"code": 1006, "title": "Resource not found", "details": "unknown contact"}]}`)), { Method: "POST", Path: "/v1/contacts", Body: `{"blocking":"wait","contacts":["+250788123123"],"force_check":true}`, - }: { - Status: 200, - Body: `{"contacts": [{"input": "+250788123123", "status": "valid", "wa_id": "250788123123"}]}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"contacts": [{"input": "+250788123123", "status": "valid", "wa_id": "250788123123"}]}`)), { Method: "POST", Path: "/v1/messages", RawQuery: "retry=1", Body: `{"to":"250788123123","type":"text","text":{"body":"try again"}}`, - }: { - Status: 201, - Body: `{"messages": [{"id": "157b5e14568e8"}]}`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{"messages": [{"id": "157b5e14568e8"}]}`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -664,32 +629,23 @@ var defaultSendTestCases = []ChannelSendTestCase{ Label: "Try Messaging Again After WhatsApp Contact Check", MsgText: "try again", MsgURN: "whatsapp:250788123123", - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"text","text":{"body":"try again"}}`, - }: { - Status: 404, - Body: `{"errors": [{"code": 1006, "title": "Resource not found", "details": "Could not retrieve phone number from contact store"}]}`, - }, + }: httpx.NewMockResponse(404, nil, []byte(`{"errors": [{"code": 1006, "title": "Resource not found", "details": "Could not retrieve phone number from contact store"}]}`)), { Method: "POST", Path: "/v1/contacts", Body: `{"blocking":"wait","contacts":["+250788123123"],"force_check":true}`, - }: { - Status: 200, - Body: `{"contacts": [{"input": "+250788123123", "status": "valid", "wa_id": "250788123123"}]}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"contacts": [{"input": "+250788123123", "status": "valid", "wa_id": "250788123123"}]}`)), { Method: "POST", Path: "/v1/messages", RawQuery: "retry=1", Body: `{"to":"250788123123","type":"text","text":{"body":"try again"}}`, - }: { - Status: 201, - Body: `{"messages": [{"id": "157b5e14568e8"}]}`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{"messages": [{"id": "157b5e14568e8"}]}`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -699,32 +655,23 @@ var defaultSendTestCases = []ChannelSendTestCase{ Label: "Try Messaging Again After WhatsApp Contact Check With Returned WhatsApp ID", MsgText: "try again", MsgURN: "whatsapp:5582999887766", - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/messages", Body: `{"to":"5582999887766","type":"text","text":{"body":"try again"}}`, - }: { - Status: 404, - Body: `{"errors": [{"code": 1006, "title": "Resource not found", "details": "unknown contact"}]}`, - }, + }: httpx.NewMockResponse(404, nil, []byte(`{"errors": [{"code": 1006, "title": "Resource not found", "details": "unknown contact"}]}`)), { Method: "POST", Path: "/v1/contacts", Body: `{"blocking":"wait","contacts":["+5582999887766"],"force_check":true}`, - }: { - Status: 200, - Body: `{"contacts": [{"input": "+5582999887766", "status": "valid", "wa_id": "558299887766"}]}`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{"contacts": [{"input": "+5582999887766", "status": "valid", "wa_id": "558299887766"}]}`)), { Method: "POST", Path: "/v1/messages", RawQuery: "retry=1", Body: `{"to":"558299887766","type":"text","text":{"body":"try again"}}`, - }: { - Status: 201, - Body: `{"messages": [{"id": "157b5e14568e8"}]}`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{"messages": [{"id": "157b5e14568e8"}]}`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -758,23 +705,17 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "whatsapp:250788123123", MsgQuickReplies: []string{"BUTTON1"}, MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -786,23 +727,17 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "whatsapp:250788123123", MsgQuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4"}, MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -829,23 +764,17 @@ var mediaCacheSendTestCases = []ChannelSendTestCase{ MsgText: "document caption", MsgURN: "whatsapp:250788123123", MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/media", Body: "media bytes", - }: { - Status: 401, - Body: `{ "errors": [{"code":1005,"title":"Access denied","details":"Invalid credentials."}] }`, - }, + }: httpx.NewMockResponse(401, nil, []byte(`{ "errors": [{"code":1005,"title":"Access denied","details":"Invalid credentials."}] }`)), { Method: "POST", Path: "/v1/messages", BodyContains: `/document.pdf`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -856,15 +785,12 @@ var mediaCacheSendTestCases = []ChannelSendTestCase{ MsgText: "document caption", MsgURN: "whatsapp:250788123123", MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/messages", BodyContains: `/document.pdf`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -875,23 +801,17 @@ var mediaCacheSendTestCases = []ChannelSendTestCase{ MsgText: "video caption", MsgURN: "whatsapp:250788123123", MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/media", Body: "media bytes", - }: { - Status: 200, - Body: `{ "media" : [{"id": "36c484d1-1283-4b94-988d-7276bdec4de2"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "media" : [{"id": "36c484d1-1283-4b94-988d-7276bdec4de2"}] }`)), { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"video","video":{"id":"36c484d1-1283-4b94-988d-7276bdec4de2","caption":"video caption"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -902,15 +822,12 @@ var mediaCacheSendTestCases = []ChannelSendTestCase{ MsgText: "video caption", MsgURN: "whatsapp:250788123123", MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"video","video":{"id":"36c484d1-1283-4b94-988d-7276bdec4de2","caption":"video caption"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -921,23 +838,17 @@ var mediaCacheSendTestCases = []ChannelSendTestCase{ MsgText: "document caption", MsgURN: "whatsapp:250788123123", MsgAttachments: []string{"application/pdf:https://foo.bar/document2.pdf"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/media", Body: "media bytes", - }: { - Status: 200, - Body: `{ "media" : [{"id": "25c484d1-1283-4b94-988d-7276bdec4ef3"}] }`, - }, + }: httpx.NewMockResponse(200, nil, []byte(`{ "media" : [{"id": "25c484d1-1283-4b94-988d-7276bdec4ef3"}] }`)), { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"document","document":{"id":"25c484d1-1283-4b94-988d-7276bdec4ef3","caption":"document caption","filename":"document2.pdf"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -948,15 +859,12 @@ var mediaCacheSendTestCases = []ChannelSendTestCase{ MsgText: "document caption", MsgURN: "whatsapp:250788123123", MsgAttachments: []string{"application/pdf:https://foo.bar/document2.pdf"}, - MockResponses: map[MockedRequest]MockedResponse{ + MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/v1/messages", Body: `{"to":"250788123123","type":"document","document":{"id":"25c484d1-1283-4b94-988d-7276bdec4ef3","caption":"document caption","filename":"document2.pdf"}}`, - }: { - Status: 201, - Body: `{ "messages": [{"id": "157b5e14568e8"}] }`, - }, + }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedStatus: "W", ExpectedExternalID: "157b5e14568e8", From 504a504aaf7f1502662c6d9525afbe7fdcd5e832 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 12 Aug 2022 14:04:35 -0500 Subject: [PATCH 069/294] Remove unncessary use of Tp utility func in tests --- .../africastalking/africastalking_test.go | 4 +- handlers/chikka/chikka_test.go | 4 +- handlers/clickatell/clickatell_test.go | 8 +- handlers/dmark/dmark_test.go | 3 +- handlers/external/external_test.go | 6 +- handlers/facebook/facebook_test.go | 24 ++-- handlers/facebookapp/facebookapp_test.go | 56 ++++----- handlers/firebase/firebase_test.go | 2 +- handlers/freshchat/freshchat_test.go | 8 +- handlers/globe/globe_test.go | 2 +- .../highconnection/highconnection_test.go | 4 +- handlers/hormuud/hormuud_test.go | 4 +- handlers/infobip/infobip_test.go | 2 +- handlers/jiochat/jiochat_test.go | 4 +- handlers/junebug/junebug_test.go | 4 +- handlers/kannel/kannel_test.go | 8 +- handlers/line/line_test.go | 14 +-- handlers/macrokiosk/macrokiosk_test.go | 6 +- handlers/mblox/mblox_test.go | 2 +- handlers/shaqodoon/shaqodoon_test.go | 4 +- handlers/start/start_test.go | 4 +- handlers/telegram/telegram_test.go | 20 ++-- handlers/test.go | 30 ++--- handlers/twitter/twitter_test.go | 4 +- handlers/vk/vk_test.go | 108 +++++++++--------- handlers/wavy/wavy_test.go | 2 +- handlers/wechat/wechat_test.go | 4 +- handlers/whatsapp/whatsapp_test.go | 22 ++-- handlers/yo/yo_test.go | 4 +- handlers/zenvia/zenvia_test.go | 12 +- handlers/zenviaold/zenviaold_test.go | 2 +- 31 files changed, 186 insertions(+), 195 deletions(-) diff --git a/handlers/africastalking/africastalking_test.go b/handlers/africastalking/africastalking_test.go index 41d6f7dd2..0070972d7 100644 --- a/handlers/africastalking/africastalking_test.go +++ b/handlers/africastalking/africastalking_test.go @@ -29,7 +29,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111"), ExpectedExternalID: Sp("ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3"), - ExpectedDate: Tp(time.Date(2017, 5, 3, 06, 04, 45, 0, time.UTC)), + ExpectedDate: time.Date(2017, 5, 3, 06, 04, 45, 0, time.UTC), }, { Label: "Receive Valid", @@ -40,7 +40,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111"), ExpectedExternalID: Sp("ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3"), - ExpectedDate: Tp(time.Date(2017, 5, 3, 06, 04, 45, 0, time.UTC)), + ExpectedDate: time.Date(2017, 5, 3, 06, 04, 45, 0, time.UTC), }, { Label: "Receive Empty", diff --git a/handlers/chikka/chikka_test.go b/handlers/chikka/chikka_test.go index 62bf14c1e..f07a7753c 100644 --- a/handlers/chikka/chikka_test.go +++ b/handlers/chikka/chikka_test.go @@ -29,8 +29,8 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("tel:+639178020779"), ExpectedExternalID: Sp("4004"), - ExpectedDate: Tp(time.Date(2016, 03, 11, 04, 20, 59, 690000128, time.UTC))}, - + ExpectedDate: time.Date(2016, 03, 11, 04, 20, 59, 690000128, time.UTC), + }, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Receive Mising Params", URL: receiveURL, Data: missingParamsReceive, ExpectedStatus: 400, ExpectedResponse: "Field validation for 'RequestID' failed"}, {Label: "Ignore Invalid message_type", URL: receiveURL, Data: "message_type=invalid", ExpectedStatus: 200, ExpectedResponse: "unknown message_type request"}, diff --git a/handlers/clickatell/clickatell_test.go b/handlers/clickatell/clickatell_test.go index a90b83bc2..b113e7ee2 100644 --- a/handlers/clickatell/clickatell_test.go +++ b/handlers/clickatell/clickatell_test.go @@ -146,16 +146,16 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Valid Receive", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Hello World!"), ExpectedURN: Sp("tel:+250788383383"), ExpectedExternalID: Sp("1234"), ExpectedDate: Tp(time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC))}, + ExpectedMsgText: Sp("Hello World!"), ExpectedURN: Sp("tel:+250788383383"), ExpectedExternalID: Sp("1234"), ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC)}, {Label: "Valid Receive ISO-8859-1", URL: receiveURL, Data: receiveValidMessageISO8859_1, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(`hello!`), ExpectedURN: Sp("tel:+250788383383"), ExpectedExternalID: Sp("1234"), ExpectedDate: Tp(time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC))}, + ExpectedMsgText: Sp(`hello!`), ExpectedURN: Sp("tel:+250788383383"), ExpectedExternalID: Sp("1234"), ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC)}, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Error invalid JSON", URL: receiveURL, Data: "foo", ExpectedStatus: 400, ExpectedResponse: `unable to parse request JSON`}, {Label: "Error missing JSON", URL: receiveURL, Data: "{}", ExpectedStatus: 400, ExpectedResponse: `missing one of 'messageId`}, {Label: "Valid Receive UTF-16BE", URL: receiveURL, Data: receiveValidMessageUTF16BE, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("mexico k mis papas no tenýa dinero para comprarnos lo q querýamos.."), ExpectedURN: Sp("tel:+250788383383"), - ExpectedExternalID: Sp("1234"), ExpectedDate: Tp(time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC))}, - + ExpectedExternalID: Sp("1234"), ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC), + }, {Label: "Valid Failed status report", URL: statusURL, Data: statusFailed, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`}, {Label: "Valid Delivered status report", URL: statusURL, Data: statusSent, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, {Label: "Unexpected status report", URL: statusURL, Data: statusUnexpected, ExpectedStatus: 400, ExpectedResponse: `unknown status '-1', must be one`}, diff --git a/handlers/dmark/dmark_test.go b/handlers/dmark/dmark_test.go index fabbe1c19..015ef5b1b 100644 --- a/handlers/dmark/dmark_test.go +++ b/handlers/dmark/dmark_test.go @@ -32,7 +32,8 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111"), - ExpectedDate: Tp(time.Date(2017, 10, 26, 15, 51, 32, 906335000, time.UTC))}, + ExpectedDate: time.Date(2017, 10, 26, 15, 51, 32, 906335000, time.UTC), + }, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Receive Empty", URL: receiveURL, Data: emptyReceive, ExpectedStatus: 400, ExpectedResponse: "field 'msisdn' required"}, {Label: "Receive Missing Text", URL: receiveURL, Data: missingText, ExpectedStatus: 400, ExpectedResponse: "field 'text' required"}, diff --git a/handlers/external/external_test.go b/handlers/external/external_test.go index 03c1e015d..d786508a8 100644 --- a/handlers/external/external_test.go +++ b/handlers/external/external_test.go @@ -55,9 +55,9 @@ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Country Parse", URL: receiveValidNoPlus, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: Tp(time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC))}, + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC)}, {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: Tp(time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC))}, + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC)}, {Label: "Invalid URN", URL: invalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from' set"}, {Label: "Receive No Sender", URL: receiveNoSender, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from' set"}, @@ -106,7 +106,7 @@ var customChannels = []courier.Channel{ var customTestCases = []ChannelHandleTestCase{ {Label: "Receive Custom Message", URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?from_number=12067799192&messageText=Join×tamp=2017-06-23T12:30:00Z", Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+12067799192"), ExpectedDate: Tp(time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC))}, + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+12067799192"), ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC)}, {Label: "Receive Custom Missing", URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sent_from=12067799192&messageText=Join", Data: "empty", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from' set"}, } diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index c4a438a04..6a3a3b36a 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -418,41 +418,41 @@ var notJSON = `blargh` var testCases = []ChannelHandleTestCase{ {Label: "Receive Message", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)}, {Label: "No Duplicate Receive Message", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: duplicateMsg, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)}, {Label: "Receive Attachment", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: attachment, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)}, {Label: "Receive Location", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: locationAttachment, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)}, {Label: "Receive Thumbs Up", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: thumbsUp, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp("👍"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, + ExpectedMsgText: Sp("👍"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)}, {Label: "Receive OptIn UserRef", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: optInUserRef, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:ref:optin_user_ref"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedURN: Sp("facebook:ref:optin_user_ref"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}}, {Label: "Receive OptIn", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: optIn, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}}, {Label: "Receive Get Started", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: postbackGetStarted, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.NewConversation), + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.NewConversation), ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}}, {Label: "Receive Referral Postback", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: postback, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}}, {Label: "Receive Referral", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: postbackReferral, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}}, {Label: "Receive Referral", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: referral, ExpectedStatus: 200, ExpectedResponse: `"referrer_id":"referral id"`, - ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}}, {Label: "Receive DLR", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: dlr, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ExpectedMsgStatus: Sp(courier.MsgDelivered), ExpectedExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233")}, + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedMsgStatus: Sp(courier.MsgDelivered), ExpectedExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233")}, {Label: "Different Page", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: differentPage, ExpectedStatus: 200, ExpectedResponse: `"data":[]`}, {Label: "Echo", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: echo, ExpectedStatus: 200, ExpectedResponse: `ignoring echo`}, diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 52cdc94c7..bd675d0e0 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -33,53 +33,53 @@ var testChannelsWAC = []courier.Channel{ var testCasesFBA = []ChannelHandleTestCase{ {Label: "Receive Message FBA", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Invalid Signature", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), ExpectedStatus: 400, ExpectedResponse: "invalid request signature", PrepRequest: addInvalidSignature}, {Label: "No Duplicate Receive Message", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/duplicateMsgFBA.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Attachment", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/attachmentFBA.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Location", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/locationAttachment.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Thumbs Up", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/thumbsUp.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp("👍"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedMsgText: Sp("👍"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive OptIn UserRef", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/optInUserRef.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:ref:optin_user_ref"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedURN: Sp("facebook:ref:optin_user_ref"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, PrepRequest: addValidSignature}, {Label: "Receive OptIn", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/optIn.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, PrepRequest: addValidSignature}, {Label: "Receive Get Started", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postbackGetStarted.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.NewConversation), + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.NewConversation), ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, PrepRequest: addValidSignature}, {Label: "Receive Referral Postback", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postback.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, PrepRequest: addValidSignature}, {Label: "Receive Referral", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postbackReferral.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, PrepRequest: addValidSignature}, {Label: "Receive Referral", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/referral.json")), ExpectedStatus: 200, ExpectedResponse: `"referrer_id":"referral id"`, - ExpectedURN: Sp("facebook:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.Referral), + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, PrepRequest: addValidSignature}, {Label: "Receive DLR", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/dlr.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ExpectedMsgStatus: Sp(courier.MsgDelivered), ExpectedExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedMsgStatus: Sp(courier.MsgDelivered), ExpectedExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233"), PrepRequest: addValidSignature}, {Label: "Different Page", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/differentPageFBA.json")), ExpectedStatus: 200, ExpectedResponse: `"data":[]`, PrepRequest: addValidSignature}, @@ -93,25 +93,25 @@ var testCasesFBA = []ChannelHandleTestCase{ } var testCasesIG = []ChannelHandleTestCase{ {Label: "Receive Message", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("instagram:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("instagram:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Invalid Signature", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), ExpectedStatus: 400, ExpectedResponse: "invalid request signature", PrepRequest: addInvalidSignature}, {Label: "No Duplicate Receive Message", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/duplicateMsgIG.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("instagram:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("instagram:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Attachment", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/attachmentIG.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, ExpectedURN: Sp("instagram:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, ExpectedURN: Sp("instagram:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Like Heart", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/like_heart.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp(""), ExpectedURN: Sp("instagram:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedMsgText: Sp(""), ExpectedURN: Sp("instagram:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Icebreaker Get Started", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/icebreakerGetStarted.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("instagram:5678"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), ChannelEvent: Sp(courier.NewConversation), + ExpectedURN: Sp("instagram:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.NewConversation), ChannelEventExtra: map[string]interface{}{"title": "icebreaker question", "payload": "get_started"}, PrepRequest: addValidSignature}, {Label: "Different Page", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/differentPageIG.json")), ExpectedStatus: 200, ExpectedResponse: `"data":[]`, PrepRequest: addValidSignature}, @@ -239,34 +239,34 @@ var wacReceiveURL = "/c/wac/receive" var testCasesWAC = []ChannelHandleTestCase{ {Label: "Receive Message WAC", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/helloWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Duplicate Valid Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/duplicateWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Voice Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/voiceWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp(""), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Voice"}, ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + ExpectedMsgText: Sp(""), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Voice"}, ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Button Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/buttonWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("No"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + ExpectedMsgText: Sp("No"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Document Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/documentWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("80skaraokesonglistartist"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Document"}, ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + ExpectedMsgText: Sp("80skaraokesonglistartist"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Document"}, ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Image Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/imageWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Check out my new phone!"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Image"}, ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + ExpectedMsgText: Sp("Check out my new phone!"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Image"}, ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Video Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/videoWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Check out my new phone!"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Video"}, ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + ExpectedMsgText: Sp("Check out my new phone!"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Video"}, ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Audio Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/audioWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Check out my new phone!"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Audio"}, ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + ExpectedMsgText: Sp("Check out my new phone!"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Audio"}, ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Location Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/locationWAC.json")), ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: "not json", ExpectedStatus: 400, ExpectedResponse: "unable to parse", PrepRequest: addValidSignature}, @@ -278,10 +278,10 @@ var testCasesWAC = []ChannelHandleTestCase{ {Label: "Receive Invalid Status", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidStatusWAC.json")), ExpectedStatus: 400, ExpectedResponse: `"unknown status: in_orbit"`, PrepRequest: addValidSignature}, {Label: "Receive Ignore Status", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/ignoreStatusWAC.json")), ExpectedStatus: 200, ExpectedResponse: `"ignoring status: deleted"`, PrepRequest: addValidSignature}, {Label: "Receive Valid Interactive Button Reply Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/buttonReplyWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Yes"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + ExpectedMsgText: Sp("Yes"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Interactive List Reply Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/listReplyWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Yes"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)), + ExpectedMsgText: Sp("Yes"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature}, } diff --git a/handlers/firebase/firebase_test.go b/handlers/firebase/firebase_test.go index 9295eeb29..2e25898e1 100644 --- a/handlers/firebase/firebase_test.go +++ b/handlers/firebase/firebase_test.go @@ -51,7 +51,7 @@ var testChannels = []courier.Channel{ var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("fcm:12345"), ExpectedDate: Tp(time.Date(2017, 1, 1, 8, 50, 0, 0, time.UTC)), ExpectedURNAuth: Sp("token"), ExpectedContactName: Sp("fred")}, + ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("fcm:12345"), ExpectedDate: time.Date(2017, 1, 1, 8, 50, 0, 0, time.UTC), ExpectedURNAuth: Sp("token"), ExpectedContactName: Sp("fred")}, {Label: "Receive Invalid Date", URL: receiveURL, Data: invalidDate, ExpectedStatus: 400, ExpectedResponse: "unable to parse date"}, {Label: "Receive Missing From", URL: receiveURL, Data: missingFrom, ExpectedStatus: 400, ExpectedResponse: "field 'from' required"}, diff --git a/handlers/freshchat/freshchat_test.go b/handlers/freshchat/freshchat_test.go index 0beb550ee..d0267010b 100644 --- a/handlers/freshchat/freshchat_test.go +++ b/handlers/freshchat/freshchat_test.go @@ -35,14 +35,14 @@ var sigtestCases = []ChannelHandleTestCase{ "Content-Type": "application/json", "X-FreshChat-Signature": validSignature}, URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Test 2"), ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), ExpectedDate: Tp(time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC))}, + ExpectedMsgText: Sp("Test 2"), ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC)}, {Label: "Bad Signature", Headers: map[string]string{ "Content-Type": "application/json", "X-FreshChat-Signature": invalidSignature}, URL: receiveURL, Data: validReceive, ExpectedStatus: 400, ExpectedResponse: `{"message":"Error","data":[{"type":"error","error":"unable to verify signature, crypto/rsa: verification error"}]}`, - ExpectedMsgText: Sp("Test 2"), ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), ExpectedDate: Tp(time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC))}, + ExpectedMsgText: Sp("Test 2"), ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC)}, } var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid w Sig", @@ -50,14 +50,14 @@ var testCases = []ChannelHandleTestCase{ "Content-Type": "application/json", "X-FreshChat-Signature": validSignature}, URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Test 2"), ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), ExpectedDate: Tp(time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC))}, + ExpectedMsgText: Sp("Test 2"), ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC)}, {Label: "Bad JSON", Headers: map[string]string{ "Content-Type": "application/json", "X-FreshChat-Signature": invalidSignature}, URL: receiveURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: `{"message":"Error","data":[{"type":"error","error":"unable to parse request JSON: invalid character 'e' looking for beginning of value"}]}`, - ExpectedMsgText: Sp("Test 2"), ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), ExpectedDate: Tp(time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC))}, + ExpectedMsgText: Sp("Test 2"), ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC)}, } func TestHandler(t *testing.T) { diff --git a/handlers/globe/globe_test.go b/handlers/globe/globe_test.go index 7592fcb58..55bfd3035 100644 --- a/handlers/globe/globe_test.go +++ b/handlers/globe/globe_test.go @@ -113,7 +113,7 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveURL, Data: validMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+639171234567"), ExpectedDate: Tp(time.Date(2013, 11, 22, 12, 12, 13, 0, time.UTC))}, + ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+639171234567"), ExpectedDate: time.Date(2013, 11, 22, 12, 12, 13, 0, time.UTC)}, {Label: "No Messages", URL: receiveURL, Data: noMessages, ExpectedStatus: 200, ExpectedResponse: "Ignored"}, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Invalid Sender", URL: receiveURL, Data: invalidSender, ExpectedStatus: 400, ExpectedResponse: "invalid 'senderAddress' parameter"}, diff --git a/handlers/highconnection/highconnection_test.go b/handlers/highconnection/highconnection_test.go index 65eccf430..3f83af7d6 100644 --- a/handlers/highconnection/highconnection_test.go +++ b/handlers/highconnection/highconnection_test.go @@ -28,10 +28,10 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("tel:+33610346460"), - ExpectedDate: Tp(time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC))}, + ExpectedDate: time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC)}, {Label: "Receive Valid Message with accents", URL: receiveURL, Data: validAccentReceive, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("je suis très satisfait "), ExpectedURN: Sp("tel:+33610346460"), - ExpectedDate: Tp(time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC))}, + ExpectedDate: time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC)}, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Receive Missing Params", URL: receiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: "validation for 'From' failed"}, diff --git a/handlers/hormuud/hormuud_test.go b/handlers/hormuud/hormuud_test.go index c89bd930d..2b31ad0a7 100644 --- a/handlers/hormuud/hormuud_test.go +++ b/handlers/hormuud/hormuud_test.go @@ -27,9 +27,9 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, + ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'sender' required"}, {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, // {Label: "Status No Params", URL: statusNoParams, Status: 400, Response: "field 'status' required"}, diff --git a/handlers/infobip/infobip_test.go b/handlers/infobip/infobip_test.go index 5274c7dc0..482ad992b 100644 --- a/handlers/infobip/infobip_test.go +++ b/handlers/infobip/infobip_test.go @@ -192,7 +192,7 @@ var invalidStatus = `{ var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveURL, Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("QUIZ Correct answer is Paris"), ExpectedURN: Sp("tel:+385916242493"), ExpectedExternalID: Sp("817790313235066447"), ExpectedDate: Tp(time.Date(2016, 10, 06, 9, 28, 39, 220000000, time.FixedZone("", 0)))}, + ExpectedMsgText: Sp("QUIZ Correct answer is Paris"), ExpectedURN: Sp("tel:+385916242493"), ExpectedExternalID: Sp("817790313235066447"), ExpectedDate: time.Date(2016, 10, 06, 9, 28, 39, 220000000, time.FixedZone("", 0))}, {Label: "Receive missing results key", URL: receiveURL, Data: missingResults, ExpectedStatus: 400, ExpectedResponse: "validation for 'Results' failed"}, {Label: "Receive missing text key", URL: receiveURL, Data: missingText, ExpectedStatus: 200, ExpectedResponse: "ignoring request, no message"}, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index 6674ec2cb..b2f169694 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -148,7 +148,7 @@ func addInvalidSignature(r *http.Request) { var testCases = []ChannelHandleTestCase{ {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("Simple Message"), ExpectedURN: Sp("jiochat:1234"), ExpectedExternalID: Sp("123456"), - ExpectedDate: Tp(time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC))}, + ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "invalid jiochat id"}, {Label: "Missing params", URL: receiveURL, Data: missingParamsRequired, ExpectedStatus: 400, ExpectedResponse: "Error:Field validation"}, @@ -157,7 +157,7 @@ var testCases = []ChannelHandleTestCase{ {Label: "Receive Image", URL: receiveURL, Data: imageMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp(""), ExpectedURN: Sp("jiochat:1234"), ExpectedExternalID: Sp("123456"), ExpectedAttachments: []string{"https://channels.jiochat.com/media/download.action?media_id=12"}, - ExpectedDate: Tp(time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC))}, + ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedStatus: 200, ExpectedResponse: "Event Accepted", ChannelEvent: Sp(courier.NewConversation), ExpectedURN: Sp("jiochat:1234")}, diff --git a/handlers/junebug/junebug_test.go b/handlers/junebug/junebug_test.go index a2bd5fe32..3b3b913d9 100644 --- a/handlers/junebug/junebug_test.go +++ b/handlers/junebug/junebug_test.go @@ -95,7 +95,7 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: inboundURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+250788383383"), - ExpectedDate: Tp(time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC))}, + ExpectedDate: time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC)}, {Label: "Invalid URN", URL: inboundURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, @@ -121,7 +121,7 @@ var authenticatedTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: inboundURL, Data: validMsg, Headers: map[string]string{"Authorization": "Token sesame"}, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+250788383383"), - ExpectedDate: Tp(time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC))}, + ExpectedDate: time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC)}, {Label: "Invalid Incoming Authorization", URL: inboundURL, Data: validMsg, Headers: map[string]string{"Authorization": "Token foo"}, ExpectedStatus: 401, ExpectedResponse: "Unauthorized"}, diff --git a/handlers/kannel/kannel_test.go b/handlers/kannel/kannel_test.go index c130a6959..6cbf30b6d 100644 --- a/handlers/kannel/kannel_test.go +++ b/handlers/kannel/kannel_test.go @@ -33,11 +33,11 @@ var ignoreChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedExternalID: Sp("asdf-asdf"), ExpectedDate: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedExternalID: Sp("asdf-asdf"), ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, {Label: "Receive KI Message", URL: receiveKIMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+68673076228"), ExpectedExternalID: Sp("asdf-asdf"), ExpectedDate: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+68673076228"), ExpectedExternalID: Sp("asdf-asdf"), ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+2349067554729"), ExpectedExternalID: Sp("asdf-asdf"), ExpectedDate: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, + ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+2349067554729"), ExpectedExternalID: Sp("asdf-asdf"), ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'sender' required"}, {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Status No Params", URL: statusNoParams, ExpectedStatus: 400, ExpectedResponse: "field 'status' required"}, @@ -47,7 +47,7 @@ var handleTestCases = []ChannelHandleTestCase{ var ignoreTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedExternalID: Sp("asdf-asdf"), ExpectedDate: Tp(time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC))}, + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedExternalID: Sp("asdf-asdf"), ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, {Label: "Write Status Delivered", URL: statusDelivered, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`}, {Label: "Ignore Status Wired", URL: statusWired, ExpectedStatus: 200, ExpectedResponse: `ignoring sent report`}, {Label: "Ignore Status Sent", URL: statusSent, ExpectedStatus: 200, ExpectedResponse: `ignoring sent report`}, diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index 33e348a17..611a0d9a9 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -259,26 +259,26 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Hello, world"), ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedMsgText: Sp("Hello, world"), ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessageLast, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Last event"), ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedMsgText: Sp("Last event"), ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Image Message", URL: receiveURL, Data: receiveValidImageMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Video Message", URL: receiveURL, Data: receiveValidVideoMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Video External Message", URL: receiveURL, Data: receiveValidVideoExternalMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://example.com/original.mp4"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://example.com/original.mp4"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Audio Message", URL: receiveURL, Data: receiveValidAudioMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Location Message", URL: receiveURL, Data: receiveValidLocationMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("my location"), ExpectedAttachments: []string{"geo:35.687574,139.729220"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)), + ExpectedMsgText: Sp("my location"), ExpectedAttachments: []string{"geo:35.687574,139.729220"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Missing message", URL: receiveURL, Data: missingMessage, ExpectedStatus: 200, ExpectedResponse: "ignoring request, no message", diff --git a/handlers/macrokiosk/macrokiosk_test.go b/handlers/macrokiosk/macrokiosk_test.go index 5cf651a90..06ada1b68 100644 --- a/handlers/macrokiosk/macrokiosk_test.go +++ b/handlers/macrokiosk/macrokiosk_test.go @@ -32,13 +32,13 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "-1", - ExpectedMsgText: Sp("Hello"), ExpectedURN: Sp("tel:+60124361111"), ExpectedDate: Tp(time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC)), + ExpectedMsgText: Sp("Hello"), ExpectedURN: Sp("tel:+60124361111"), ExpectedDate: time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC), ExpectedExternalID: Sp("abc1234")}, {Label: "Receive Valid via GET", URL: receiveURL + "?" + validReceive, ExpectedStatus: 200, ExpectedResponse: "-1", - ExpectedMsgText: Sp("Hello"), ExpectedURN: Sp("tel:+60124361111"), ExpectedDate: Tp(time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC)), + ExpectedMsgText: Sp("Hello"), ExpectedURN: Sp("tel:+60124361111"), ExpectedDate: time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC), ExpectedExternalID: Sp("abc1234")}, {Label: "Receive Valid", URL: receiveURL, Data: validLongcodeReceive, ExpectedStatus: 200, ExpectedResponse: "-1", - ExpectedMsgText: Sp("Hello"), ExpectedURN: Sp("tel:+60124361111"), ExpectedDate: Tp(time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC)), + ExpectedMsgText: Sp("Hello"), ExpectedURN: Sp("tel:+60124361111"), ExpectedDate: time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC), ExpectedExternalID: Sp("abc1234")}, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Missing Params", URL: receiveURL, Data: missingParamsReceive, ExpectedStatus: 400, ExpectedResponse: "missing shortcode, longcode, from or msisdn parameters"}, diff --git a/handlers/mblox/mblox_test.go b/handlers/mblox/mblox_test.go index 768d181ef..d6584a41e 100644 --- a/handlers/mblox/mblox_test.go +++ b/handlers/mblox/mblox_test.go @@ -63,7 +63,7 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("tel:+12067799294"), ExpectedDate: Tp(time.Date(2016, 3, 30, 19, 33, 06, 643000000, time.UTC)), + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("tel:+12067799294"), ExpectedDate: time.Date(2016, 3, 30, 19, 33, 06, 643000000, time.UTC), ExpectedExternalID: Sp("OzQ5UqIOdoY8")}, {Label: "Receive Missing Params", URL: receiveURL, Data: missingParamsRecieve, ExpectedStatus: 400, ExpectedResponse: "missing one of 'id', 'from', 'to', 'body' or 'received_at' in request body"}, diff --git a/handlers/shaqodoon/shaqodoon_test.go b/handlers/shaqodoon/shaqodoon_test.go index c960bece7..36f15f6a8 100644 --- a/handlers/shaqodoon/shaqodoon_test.go +++ b/handlers/shaqodoon/shaqodoon_test.go @@ -34,9 +34,9 @@ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+2349067554729")}, {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: Tp(time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC))}, + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC)}, {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: Tp(time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC))}, + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC)}, {Label: "Receive invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'from' required"}, {Label: "Receive No Sender", URL: receiveNoSender, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'from' required"}, diff --git a/handlers/start/start_test.go b/handlers/start/start_test.go index a9963f4c0..92b029a7c 100644 --- a/handlers/start/start_test.go +++ b/handlers/start/start_test.go @@ -75,9 +75,9 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("tel:+250788123123"), ExpectedDate: Tp(time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC))}, + ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("tel:+250788123123"), ExpectedDate: time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC)}, {Label: "Receive Valid Encoded", URL: receiveURL, Data: validReceiveEncoded, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Кохання"), ExpectedURN: Sp("tel:+380501529999"), ExpectedDate: Tp(time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC))}, + ExpectedMsgText: Sp("Кохання"), ExpectedURN: Sp("tel:+380501529999"), ExpectedDate: time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC)}, {Label: "Receive Valid with empty Text", URL: receiveURL, Data: validReceiveEmptyText, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+250788123123")}, {Label: "Receive Valid missing body", URL: receiveURL, Data: validMissingBody, ExpectedStatus: 200, ExpectedResponse: "Accepted", diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index 07801930f..4ce3cef2b 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -453,38 +453,38 @@ var contactMsg = ` var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Start Message", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: startMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ChannelEvent: Sp(string(courier.NewConversation)), ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + ExpectedContactName: Sp("Nic Pottier"), ChannelEvent: Sp(string(courier.NewConversation)), ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive No Params", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: emptyMsg, ExpectedStatus: 200, ExpectedResponse: "Ignoring"}, {Label: "Receive Invalid JSON", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: "foo", ExpectedStatus: 400, ExpectedResponse: "unable to parse"}, {Label: "Receive Sticker", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: stickerMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/sticker.jpg"}, ExpectedURN: Sp("telegram:3527065"), ExpectedExternalID: Sp("44"), ExpectedDate: Tp(time.Date(2016, 1, 30, 2, 07, 48, 0, time.UTC))}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/sticker.jpg"}, ExpectedURN: Sp("telegram:3527065"), ExpectedExternalID: Sp("44"), ExpectedDate: time.Date(2016, 1, 30, 2, 07, 48, 0, time.UTC)}, {Label: "Receive Photo", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: photoMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Photo Caption"), ExpectedAttachments: []string{"/file/bota123/photo.jpg"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("85"), ExpectedDate: Tp(time.Date(2017, 5, 3, 20, 28, 38, 0, time.UTC))}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Photo Caption"), ExpectedAttachments: []string{"/file/bota123/photo.jpg"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("85"), ExpectedDate: time.Date(2017, 5, 3, 20, 28, 38, 0, time.UTC)}, {Label: "Receive Video", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: videoMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/video.jpg"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("86"), ExpectedDate: Tp(time.Date(2017, 5, 3, 20, 29, 24, 0, time.UTC))}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/video.jpg"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("86"), ExpectedDate: time.Date(2017, 5, 3, 20, 29, 24, 0, time.UTC)}, {Label: "Receive Voice", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: voiceMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/voice.mp4"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("91"), ExpectedDate: Tp(time.Date(2017, 5, 3, 20, 50, 46, 0, time.UTC))}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/voice.mp4"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("91"), ExpectedDate: time.Date(2017, 5, 3, 20, 50, 46, 0, time.UTC)}, {Label: "Receive Document", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: documentMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/document.xls"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("92"), ExpectedDate: Tp(time.Date(2017, 5, 3, 20, 58, 20, 0, time.UTC))}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/document.xls"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("92"), ExpectedDate: time.Date(2017, 5, 3, 20, 58, 20, 0, time.UTC)}, {Label: "Receive Location", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: locationMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("-2.890287,-79.004333"), ExpectedAttachments: []string{"geo:-2.890287,-79.004333"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("94"), ExpectedDate: Tp(time.Date(2017, 5, 3, 21, 00, 44, 0, time.UTC))}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("-2.890287,-79.004333"), ExpectedAttachments: []string{"geo:-2.890287,-79.004333"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("94"), ExpectedDate: time.Date(2017, 5, 3, 21, 00, 44, 0, time.UTC)}, {Label: "Receive Venue", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: venueMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Cuenca, Provincia del Azuay"), ExpectedAttachments: []string{"geo:-2.898944,-79.006835"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("95"), ExpectedDate: Tp(time.Date(2017, 5, 3, 21, 05, 20, 0, time.UTC))}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Cuenca, Provincia del Azuay"), ExpectedAttachments: []string{"geo:-2.898944,-79.006835"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("95"), ExpectedDate: time.Date(2017, 5, 3, 21, 05, 20, 0, time.UTC)}, {Label: "Receive Contact", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: contactMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Adolf Taxi (0788531373)"), ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("96"), ExpectedDate: Tp(time.Date(2017, 5, 3, 21, 9, 15, 0, time.UTC))}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Adolf Taxi (0788531373)"), ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("96"), ExpectedDate: time.Date(2017, 5, 3, 21, 9, 15, 0, time.UTC)}, {Label: "Receive Empty", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: emptyMsg, ExpectedStatus: 200, ExpectedResponse: "Ignoring"}, diff --git a/handlers/test.go b/handlers/test.go index e3183e88e..e8127d384 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -44,7 +44,7 @@ type ChannelHandleTestCase struct { ExpectedURN *string ExpectedURNAuth *string ExpectedAttachments []string - ExpectedDate *time.Time + ExpectedDate time.Time ExpectedMsgStatus *string ExpectedExternalID *string ExpectedMsgID int64 @@ -108,20 +108,6 @@ type ChannelSendTestCase struct { // Sp is a utility method to get the pointer to the passed in string func Sp(str interface{}) *string { asStr := fmt.Sprintf("%s", str); return &asStr } -// Tp is utility method to get the pointer to the passed in time -func Tp(tm time.Time) *time.Time { return &tm } - -// utility method to make sure the passed in host is up, prevents races with our test server -func ensureTestServerUp(host string) { - for i := 0; i < 20; i++ { - _, err := http.Get(host) - if err == nil { - break - } - time.Sleep(time.Microsecond * 100) - } -} - // utility method to make a request to a handler URL func testHandlerRequest(tb testing.TB, s courier.Server, path string, headers map[string]string, data string, multipartFormFields map[string]string, expectedStatus int, expectedBody *string, requestPrepFunc RequestPrepFunc) string { var req *http.Request @@ -159,10 +145,8 @@ func testHandlerRequest(tb testing.TB, s courier.Server, path string, headers ma req, err = http.NewRequest(http.MethodGet, url, nil) } - if headers != nil { - for key, val := range headers { - req.Header.Set(key, val) - } + for key, val := range headers { + req.Header.Set(key, val) } require.Nil(tb, err) @@ -429,13 +413,13 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri if len(tc.ExpectedAttachments) > 0 { require.Equal(tc.ExpectedAttachments, msg.Attachments()) } - if tc.ExpectedDate != nil { + if !tc.ExpectedDate.IsZero() { if msg != nil { - require.Equal((*tc.ExpectedDate).Local(), (*msg.ReceivedOn()).Local()) + require.Equal((tc.ExpectedDate).Local(), (*msg.ReceivedOn()).Local()) } else if event != nil { - require.Equal(*tc.ExpectedDate, event.OccurredOn()) + require.Equal(tc.ExpectedDate, event.OccurredOn()) } else { - require.Equal(*tc.ExpectedDate, nil) + require.Equal(tc.ExpectedDate, nil) } } } diff --git a/handlers/twitter/twitter_test.go b/handlers/twitter/twitter_test.go index 5bf1b3242..eda1ea3b4 100644 --- a/handlers/twitter/twitter_test.go +++ b/handlers/twitter/twitter_test.go @@ -169,9 +169,9 @@ var notJSON = `blargh` var testCases = []ChannelHandleTestCase{ {Label: "Receive Message", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedContactName: Sp("Nicolas Pottier"), ExpectedURN: Sp("twitterid:272953809#nicpottier"), - ExpectedMsgText: Sp("Hello World & good wishes."), ExpectedExternalID: Sp("958501034212564996"), ExpectedDate: Tp(time.Date(2018, 1, 31, 0, 43, 49, 301000000, time.UTC))}, + ExpectedMsgText: Sp("Hello World & good wishes."), ExpectedExternalID: Sp("958501034212564996"), ExpectedDate: time.Date(2018, 1, 31, 0, 43, 49, 301000000, time.UTC)}, {Label: "Receive Attachment", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: attachment, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Hello"), ExpectedAttachments: []string{"https://image.foo.com/image.jpg"}, ExpectedURN: Sp("twitterid:272953809#nicpottier"), ExpectedExternalID: Sp("958501034212564996"), ExpectedDate: Tp(time.Date(2018, 1, 31, 0, 43, 49, 301000000, time.UTC))}, + ExpectedMsgText: Sp("Hello"), ExpectedAttachments: []string{"https://image.foo.com/image.jpg"}, ExpectedURN: Sp("twitterid:272953809#nicpottier"), ExpectedExternalID: Sp("958501034212564996"), ExpectedDate: time.Date(2018, 1, 31, 0, 43, 49, 301000000, time.UTC)}, {Label: "Not JSON", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "Error"}, {Label: "Invalid Twitter handle", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidTwitterHandle, ExpectedStatus: 400, ExpectedResponse: "invalid twitter handle"}, {Label: "Invalid Twitter ID", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidTwitterID, ExpectedStatus: 400, ExpectedResponse: "invalid twitter id"}, diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index 431d198c8..5e8774db7 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -238,7 +238,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedResponse: "ok", ExpectedURN: Sp("vk:123456"), ExpectedExternalID: Sp("1"), - ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), }, { Label: "Receive Empty Message", @@ -248,57 +248,62 @@ var testCases = []ChannelHandleTestCase{ ExpectedResponse: "no text or attachment", ExpectedURN: Sp("vk:123456"), ExpectedExternalID: Sp("1"), - ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), }, { - Label: "Receive First Photo Attachment", - URL: receiveURL, - Data: msgFirstPhotoAttachment, - ExpectedStatus: 200, - ExpectedResponse: "ok", - ExpectedURN: Sp("vk:123456"), - ExpectedExternalID: Sp("1"), - ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), ExpectedAttachments: []string{"https://foo.bar/x-photo.jpg"}, + Label: "Receive First Photo Attachment", + URL: receiveURL, + Data: msgFirstPhotoAttachment, + ExpectedStatus: 200, + ExpectedResponse: "ok", + ExpectedURN: Sp("vk:123456"), + ExpectedExternalID: Sp("1"), + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), + ExpectedAttachments: []string{"https://foo.bar/x-photo.jpg"}, }, { - Label: "Receive First Graffiti Attachment", - URL: receiveURL, - Data: msgFirstGraffitiAttachment, - ExpectedStatus: 200, - ExpectedResponse: "ok", - ExpectedURN: Sp("vk:123456"), - ExpectedExternalID: Sp("1"), - ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), ExpectedAttachments: []string{"https://foo.bar/graffiti.png"}, + Label: "Receive First Graffiti Attachment", + URL: receiveURL, + Data: msgFirstGraffitiAttachment, + ExpectedStatus: 200, + ExpectedResponse: "ok", + ExpectedURN: Sp("vk:123456"), + ExpectedExternalID: Sp("1"), + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), + ExpectedAttachments: []string{"https://foo.bar/graffiti.png"}, }, { - Label: "Receive First Sticker Attachment", - URL: receiveURL, - Data: msgFirstStickerAttachment, - ExpectedStatus: 200, - ExpectedResponse: "ok", - ExpectedURN: Sp("vk:123456"), - ExpectedExternalID: Sp("1"), - ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), ExpectedAttachments: []string{"https://foo.bar/128x128_sticker.png"}, + Label: "Receive First Sticker Attachment", + URL: receiveURL, + Data: msgFirstStickerAttachment, + ExpectedStatus: 200, + ExpectedResponse: "ok", + ExpectedURN: Sp("vk:123456"), + ExpectedExternalID: Sp("1"), + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), + ExpectedAttachments: []string{"https://foo.bar/128x128_sticker.png"}, }, { - Label: "Receive First Audio Attachment", - URL: receiveURL, - Data: msgFirstAudioAttachment, - ExpectedStatus: 200, - ExpectedResponse: "ok", - ExpectedURN: Sp("vk:123456"), - ExpectedExternalID: Sp("1"), - ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), ExpectedAttachments: []string{"https://foo.bar/audio.mp3"}, + Label: "Receive First Audio Attachment", + URL: receiveURL, + Data: msgFirstAudioAttachment, + ExpectedStatus: 200, + ExpectedResponse: "ok", + ExpectedURN: Sp("vk:123456"), + ExpectedExternalID: Sp("1"), + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), + ExpectedAttachments: []string{"https://foo.bar/audio.mp3"}, }, { - Label: "Receive First Audio Attachment", - URL: receiveURL, - Data: msgFirstDocAttachment, - ExpectedStatus: 200, - ExpectedResponse: "ok", - ExpectedURN: Sp("vk:123456"), - ExpectedExternalID: Sp("1"), - ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), ExpectedAttachments: []string{"https://foo.bar/doc.pdf"}, + Label: "Receive First Audio Attachment", + URL: receiveURL, + Data: msgFirstDocAttachment, + ExpectedStatus: 200, + ExpectedResponse: "ok", + ExpectedURN: Sp("vk:123456"), + ExpectedExternalID: Sp("1"), + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), + ExpectedAttachments: []string{"https://foo.bar/doc.pdf"}, }, { Label: "Receive Message Keyboard", @@ -308,17 +313,18 @@ var testCases = []ChannelHandleTestCase{ ExpectedResponse: "ok", ExpectedURN: Sp("vk:123456"), ExpectedExternalID: Sp("1"), - ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), }, { - Label: "Receive Geolocation Attachment", - URL: receiveURL, - Data: msgGeolocationOnly, - ExpectedStatus: 200, - ExpectedResponse: "ok", - ExpectedURN: Sp("vk:123456"), - ExpectedExternalID: Sp("1"), - ExpectedDate: Tp(time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC)), ExpectedAttachments: []string{"geo:-9.652278,-35.701095"}, + Label: "Receive Geolocation Attachment", + URL: receiveURL, + Data: msgGeolocationOnly, + ExpectedStatus: 200, + ExpectedResponse: "ok", + ExpectedURN: Sp("vk:123456"), + ExpectedExternalID: Sp("1"), + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), + ExpectedAttachments: []string{"geo:-9.652278,-35.701095"}, }, { Label: "Validate secret", diff --git a/handlers/wavy/wavy_test.go b/handlers/wavy/wavy_test.go index fbd0e8c6b..acd02542a 100644 --- a/handlers/wavy/wavy_test.go +++ b/handlers/wavy/wavy_test.go @@ -80,7 +80,7 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Message", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Eu quero pizza"), ExpectedURN: Sp("tel:+5516981562820"), ExpectedExternalID: Sp("external_id"), ExpectedDate: Tp(time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC))}, + ExpectedMsgText: Sp("Eu quero pizza"), ExpectedURN: Sp("tel:+5516981562820"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)}, {Label: "Invalid JSON receive", URL: receiveURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, {Label: "Missing Keys receive", URL: receiveURL, Data: missingRequiredKeys, ExpectedStatus: 400, ExpectedResponse: "validation for 'ID' failed on the 'required'"}, diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index ea91d2a94..441a13317 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -145,7 +145,7 @@ func addInvalidSignature(r *http.Request) { var testCases = []ChannelHandleTestCase{ {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "", ExpectedMsgText: Sp("Simple Message"), ExpectedURN: Sp("wechat:1234"), ExpectedExternalID: Sp("123456"), - ExpectedDate: Tp(time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC))}, + ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, {Label: "Missing params", URL: receiveURL, Data: missingParamsRequired, ExpectedStatus: 400, ExpectedResponse: "Error:Field validation"}, {Label: "Missing params Event or MsgId", URL: receiveURL, Data: missingParams, ExpectedStatus: 400, ExpectedResponse: "missing parameters, must have either 'MsgId' or 'Event'"}, @@ -153,7 +153,7 @@ var testCases = []ChannelHandleTestCase{ {Label: "Receive Image", URL: receiveURL, Data: imageMessage, ExpectedStatus: 200, ExpectedResponse: "", ExpectedMsgText: Sp(""), ExpectedURN: Sp("wechat:1234"), ExpectedExternalID: Sp("123456"), ExpectedAttachments: []string{"https://api.weixin.qq.com/cgi-bin/media/get?media_id=12"}, - ExpectedDate: Tp(time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC))}, + ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedStatus: 200, ExpectedResponse: "Event Accepted", ChannelEvent: Sp(courier.NewConversation), ExpectedURN: Sp("wechat:1234")}, diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index 5602a1461..6523e70ed 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -293,27 +293,27 @@ var ( var waTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: waReceiveURL, Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedContactName: Sp("Jerry Cooney"), ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + ExpectedContactName: Sp("Jerry Cooney"), ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Duplicate Valid Message", URL: waReceiveURL, Data: duplicateMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Audio Message", URL: waReceiveURL, Data: audioMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Button Message", URL: waReceiveURL, Data: buttonMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp("BUTTON1"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + ExpectedMsgText: Sp("BUTTON1"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Document Message", URL: waReceiveURL, Data: documentMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp("the caption"), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + ExpectedMsgText: Sp("the caption"), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Image Message", URL: waReceiveURL, Data: imageMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp("the caption"), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + ExpectedMsgText: Sp("the caption"), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Interactive Button Message", URL: waReceiveURL, Data: interactiveButtonMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp("BUTTON1"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + ExpectedMsgText: Sp("BUTTON1"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Interactive List Message", URL: waReceiveURL, Data: interactiveListMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp("ROW1"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + ExpectedMsgText: Sp("ROW1"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Location Message", URL: waReceiveURL, Data: locationMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Video Message", URL: waReceiveURL, Data: videoMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Voice Message", URL: waReceiveURL, Data: voiceMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: Tp(time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC))}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: invalidMsg, ExpectedStatus: 400, ExpectedResponse: "unable to parse"}, {Label: "Receive Invalid From", URL: waReceiveURL, Data: invalidFrom, ExpectedStatus: 400, ExpectedResponse: "invalid whatsapp id"}, {Label: "Receive Invalid Timestamp", URL: waReceiveURL, Data: invalidTimestamp, ExpectedStatus: 400, ExpectedResponse: "invalid timestamp"}, diff --git a/handlers/yo/yo_test.go b/handlers/yo/yo_test.go index bb2123091..bdd351a58 100644 --- a/handlers/yo/yo_test.go +++ b/handlers/yo/yo_test.go @@ -31,9 +31,9 @@ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid From", URL: receiveValidMessageFrom, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: Tp(time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC))}, + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC)}, {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: Tp(time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC))}, + ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC)}, {Label: "Invalid URN", URL: receiveInvalidURN, Data: "", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Receive No Params", URL: receiveNoParams, Data: "", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from'"}, {Label: "Receive No Sender", URL: receiveNoSender, Data: "", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from'"}, diff --git a/handlers/zenvia/zenvia_test.go b/handlers/zenvia/zenvia_test.go index 8dddffb75..6c910a011 100644 --- a/handlers/zenvia/zenvia_test.go +++ b/handlers/zenvia/zenvia_test.go @@ -197,13 +197,13 @@ var missingFieldsReceive = `{ var testWhatappCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveWhatsappURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, {Label: "Receive file Valid", URL: receiveWhatsappURL, Data: fileReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, {Label: "Receive location Valid", URL: receiveWhatsappURL, Data: locationReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, {Label: "Not JSON body", URL: receiveWhatsappURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, {Label: "Wrong JSON schema", URL: receiveWhatsappURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, @@ -218,13 +218,13 @@ var testWhatappCases = []ChannelHandleTestCase{ var testSMSCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveSMSURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, {Label: "Receive file Valid", URL: receiveSMSURL, Data: fileReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, {Label: "Receive location Valid", URL: receiveSMSURL, Data: locationReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: Tp(time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC))}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, {Label: "Not JSON body", URL: receiveSMSURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, {Label: "Wrong JSON schema", URL: receiveSMSURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, diff --git a/handlers/zenviaold/zenviaold_test.go b/handlers/zenviaold/zenviaold_test.go index b8001840d..cd56ee90f 100644 --- a/handlers/zenviaold/zenviaold_test.go +++ b/handlers/zenviaold/zenviaold_test.go @@ -106,7 +106,7 @@ var missingFieldsReceive = `{ var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111"), ExpectedDate: Tp(time.Date(2017, 5, 3, 06, 04, 45, 123000000, time.UTC))}, + ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111"), ExpectedDate: time.Date(2017, 5, 3, 06, 04, 45, 123000000, time.UTC)}, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Not JSON body", URL: receiveURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, From 6ee4403cb0a26952ab9c6802c6c62c47ba79db2f Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 12 Aug 2022 15:22:16 -0500 Subject: [PATCH 070/294] Misc cleanup --- handlers/facebook/facebook_test.go | 162 ++++++++++++++++++--------- handlers/forms.go | 5 +- handlers/freshchat/freshchat_test.go | 60 +++++----- handlers/test.go | 21 ++-- 4 files changed, 148 insertions(+), 100 deletions(-) diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index 6a3a3b36a..202a31e8f 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -562,68 +562,120 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "facebook:12345", - ExpectedStatus: "W", ExpectedExternalID: "mid.133", - MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "facebook:12345", + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, - SendPrep: setSendURL}, - {Label: "Plain Response", - MsgText: "Simple Message", MsgURN: "facebook:12345", - ExpectedStatus: "W", ExpectedExternalID: "mid.133", MsgResponseToExternalID: "23526", - MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, - ExpectedRequestBody: `{"messaging_type":"RESPONSE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, - SendPrep: setSendURL}, - {Label: "Plain Send using ref URN", - MsgText: "Simple Message", MsgURN: "facebook:ref:67890", - ExpectedContactURNs: map[string]bool{"facebook:12345": true, "ext:67890": true, "facebook:ref:67890": false}, - ExpectedStatus: "W", ExpectedExternalID: "mid.133", - MockResponseBody: `{"message_id": "mid.133", "recipient_id": "12345"}`, MockResponseStatus: 200, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "Plain Response", + MsgText: "Simple Message", + MsgURN: "facebook:12345", + MsgResponseToExternalID: "23526", + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"messaging_type":"RESPONSE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "Plain Send using ref URN", + MsgText: "Simple Message", + MsgURN: "facebook:ref:67890", + MockResponseBody: `{"message_id": "mid.133", "recipient_id": "12345"}`, + MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"user_ref":"67890"},"message":{"text":"Simple Message"}}`, - SendPrep: setSendURL}, - {Label: "Quick Reply", - MsgText: "Are you happy?", MsgURN: "facebook:12345", MsgQuickReplies: []string{"Yes", "No"}, - ExpectedStatus: "W", ExpectedExternalID: "mid.133", - MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, + ExpectedContactURNs: map[string]bool{"facebook:12345": true, "ext:67890": true, "facebook:ref:67890": false}, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "Quick Reply", + MsgText: "Are you happy?", + MsgURN: "facebook:12345", + MsgQuickReplies: []string{"Yes", "No"}, + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"id":"12345"},"message":{"text":"Are you happy?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - SendPrep: setSendURL}, - {Label: "Long Message", - MsgText: "This is a long message which spans more than one part, what will actually be sent in the end if we exceed the max length?", - MsgURN: "facebook:12345", MsgQuickReplies: []string{"Yes", "No"}, MsgTopic: "account", - ExpectedStatus: "W", ExpectedExternalID: "mid.133", - MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "Long Message", + MsgText: "This is a long message which spans more than one part, what will actually be sent in the end if we exceed the max length?", + MsgURN: "facebook:12345", + MsgQuickReplies: []string{"Yes", "No"}, + MsgTopic: "account", + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"ACCOUNT_UPDATE","recipient":{"id":"12345"},"message":{"text":"we exceed the max length?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - SendPrep: setSendURL}, - {Label: "Send Photo", - MsgURN: "facebook:12345", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", ExpectedExternalID: "mid.133", - MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, + SendPrep: setSendURL, + }, + { + Label: "Send Photo", + MsgURN: "facebook:12345", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"id":"12345"},"message":{"attachment":{"type":"image","payload":{"url":"https://foo.bar/image.jpg","is_reusable":true}}}}`, - SendPrep: setSendURL}, - {Label: "Send caption and photo with Quick Reply", - MsgText: "This is some text.", - MsgURN: "facebook:12345", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MsgQuickReplies: []string{"Yes", "No"}, MsgTopic: "event", - ExpectedStatus: "W", ExpectedExternalID: "mid.133", - MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, + SendPrep: setSendURL, + }, + { + Label: "Send caption and photo with Quick Reply", + MsgText: "This is some text.", + MsgURN: "facebook:12345", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MsgQuickReplies: []string{"Yes", "No"}, + MsgTopic: "event", + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"CONFIRMED_EVENT_UPDATE","recipient":{"id":"12345"},"message":{"text":"This is some text.","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - SendPrep: setSendURL}, - {Label: "Send Document", - MsgURN: "facebook:12345", MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, - ExpectedStatus: "W", ExpectedExternalID: "mid.133", - MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "Send Document", + MsgURN: "facebook:12345", + MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, + MockResponseBody: `{"message_id": "mid.133"}`, + MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"id":"12345"},"message":{"attachment":{"type":"file","payload":{"url":"https://foo.bar/document.pdf","is_reusable":true}}}}`, - SendPrep: setSendURL}, - {Label: "ID Error", - MsgText: "ID Error", MsgURN: "facebook:12345", - ExpectedStatus: "E", - MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Error", - MsgText: "Error", MsgURN: "facebook:12345", - ExpectedStatus: "E", - MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 403, - SendPrep: setSendURL}, + ExpectedStatus: "W", + ExpectedExternalID: "mid.133", + SendPrep: setSendURL, + }, + { + Label: "ID Error", + MsgText: "ID Error", + MsgURN: "facebook:12345", + MockResponseBody: `{ "is_error": true }`, + MockResponseStatus: 200, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error", + MsgText: "Error", + MsgURN: "facebook:12345", + MockResponseBody: `{ "is_error": true }`, + MockResponseStatus: 403, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/forms.go b/handlers/forms.go index a13294906..aeee24900 100644 --- a/handlers/forms.go +++ b/handlers/forms.go @@ -6,7 +6,6 @@ import ( "encoding/xml" "fmt" "io" - "io/ioutil" "net/http" "github.com/gorilla/schema" @@ -96,8 +95,8 @@ func DecodeAndValidateXML(envelope interface{}, r *http.Request) error { // ReadBody of a HTTP request up to limit bytes and make sure the Body is not consumed func ReadBody(r *http.Request, limit int64) ([]byte, error) { - body, err := ioutil.ReadAll(io.LimitReader(r.Body, limit)) - r.Body = ioutil.NopCloser(bytes.NewBuffer(body)) + body, err := io.ReadAll(io.LimitReader(r.Body, limit)) + r.Body = io.NopCloser(bytes.NewBuffer(body)) return body, err } diff --git a/handlers/freshchat/freshchat_test.go b/handlers/freshchat/freshchat_test.go index d0267010b..11926f535 100644 --- a/handlers/freshchat/freshchat_test.go +++ b/handlers/freshchat/freshchat_test.go @@ -27,8 +27,8 @@ var ( validSignature = `AhrmypOSWoewHG6LmIRuWjxyokuMDmPklrSU9p0gpUNjdSRCJzvpL6rjuTi5poV/ZLzWRWNM7X9yWjT5m9YFPshYrvigcd1ph4Ot2xmaJGYoUNJHijQccE6oDtDIp6i/8oLRafHgObQnGukZWPbP9OE5EiKz/VcsMP0Wv7hawI/sfIviM0w+6fNOKXWi0jDBH9ap1mj5CqOUOojni7OD5iYmIrjV/h33dyNmbvAta9E+trzcEhYqxfHIN4Z8R2FsatfRHWicoQ4PE5cQ8+UONVya8qr85nQ9w8N7Ql7yNg9fEViYG4/W/JnGEbPPEf8WrYtKzoVyuupDz4mVHdfKWg==` validReceive = `{"actor":{"actor_type":"user","actor_id":"882f3926-b292-414b-a411-96380db373cd"},"action":"message_create","action_time":"2019-06-21T17:43:20.875Z","data":{"message":{"message_parts":[{"text":{"content":"Test 2"}}],"app_id":"55b190fa-5d3c-45c4-bc49-74ddcfcf53d7","actor_id":"882f3926-b292-414b-a411-96380db373cd","id":"7a454fde-c720-4c97-a61d-0ffe70449eb6","channel_id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606","conversation_id":"c327498e-f713-481e-8d83-0603e03d2521","message_type":"normal","actor_type":"user","created_time":"2019-06-21T17:43:20.866Z"}}}` invalidSignature = `f7wMD1BBhcj60U0z3dCY519qmxQ8qfVUU212Dapw9vpZfRBfjjmukUK2GwbAb0Nc+TGQHxN4iP4WD+Y/mSx6f4bmkBsvCy3l4OCQ/FEK0y5R7f+GLLDhgbTh90MwuLDHhvxB5dxIeu59leL+4yO+l/8M3Tm48aQurVBi9IAlzFsMtc1S1CiRxsDUb/rD6IRekPa0pUAbkno9qJ/CGXh0kZMdsYzRkzZmKCs79OWrvU94ha0ptyt5wArfmD1oSzY3PjeL2w8LWDc0QV21H/Hvj42azIUqebiNRtZ2E+f34AfQsyfcPuy1k/6qLuYGOdU1uZidPuPcGpeSIm0GW6k9HQ==` - invalidURN = `{"actor":{"actor_type":"user","actor_id":"c0534ff79-8853-11cedfc1f35b"},"action":"message_create","action_time":"2019-06-21T14:21:35.042Z","data":{"message":{"message_parts":[{"text":{"content":"test"}}],"app_id":"55b190fa-5d3c-45c4-bc49-74ddcfcf53d7","actor_id":"c0534f78-b6e9-4f79-8853-11cedfc1f35b","id":"3fce6f90-a01a-44a9-8ab1-8feea6ebc95b","channel_id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606","conversation_id":"c327498e-f713-481e-8d83-0603e03d2521","message_type":"normal","actor_type":"user","created_time":"2019-06-21T14:21:35Z"}}}` ) + var sigtestCases = []ChannelHandleTestCase{ {Label: "Receive Valid w Signature", Headers: map[string]string{ @@ -74,47 +74,41 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message ☺", - MsgURN: "freshchat:0534f78-b6e9-4f79-8853-11cedfc1f35b/c8fddfaf-622a-4a0e-b060-4f3ccbeab606", - ExpectedStatus: "W", - ExpectedExternalID: "", - MockResponseBody: "", - MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Authorization": "Bearer enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", - }, + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "freshchat:0534f78-b6e9-4f79-8853-11cedfc1f35b/c8fddfaf-622a-4a0e-b060-4f3ccbeab606", + MockResponseBody: "", + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Authorization": "Bearer enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ="}, ExpectedRequestBody: `{"messages":[{"message_parts":[{"text":{"content":"Simple Message ☺"}}],"actor_id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606","actor_type":"agent"}],"channel_id":"0534f78-b6e9-4f79-8853-11cedfc1f35b","users":[{"id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606"}]}`, + ExpectedStatus: "W", + ExpectedExternalID: "", SendPrep: setSendURL, }, - {Label: "Send with text and image", - MsgText: "Simple Message ☺", - MsgURN: "freshchat:0534f78-b6e9-4f79-8853-11cedfc1f35b/c8fddfaf-622a-4a0e-b060-4f3ccbeab606", - ExpectedStatus: "W", - ExpectedExternalID: "", - MockResponseBody: "", - MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Authorization": "Bearer enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", - }, + { + Label: "Send with text and image", + MsgText: "Simple Message ☺", + MsgURN: "freshchat:0534f78-b6e9-4f79-8853-11cedfc1f35b/c8fddfaf-622a-4a0e-b060-4f3ccbeab606", MsgAttachments: []string{"image:https://foo.bar/image.jpg"}, + MockResponseBody: "", + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Authorization": "Bearer enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ="}, ExpectedRequestBody: `{"messages":[{"message_parts":[{"text":{"content":"Simple Message ☺"}},{"image":{"url":"https://foo.bar/image.jpg"}}],"actor_id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606","actor_type":"agent"}],"channel_id":"0534f78-b6e9-4f79-8853-11cedfc1f35b","users":[{"id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606"}]}`, + ExpectedStatus: "W", + ExpectedExternalID: "", SendPrep: setSendURL, }, - {Label: "Send with image only", - MsgURN: "freshchat:0534f78-b6e9-4f79-8853-11cedfc1f35b/c8fddfaf-622a-4a0e-b060-4f3ccbeab606", - ExpectedStatus: "W", - ExpectedExternalID: "", - MockResponseBody: "", - MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Authorization": "Bearer enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", - }, + { + Label: "Send with image only", + MsgURN: "freshchat:0534f78-b6e9-4f79-8853-11cedfc1f35b/c8fddfaf-622a-4a0e-b060-4f3ccbeab606", MsgAttachments: []string{"image/jpg:https://foo.bar/image.jpg"}, + MockResponseBody: "", + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Authorization": "Bearer enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ="}, ExpectedRequestBody: `{"messages":[{"message_parts":[{"image":{"url":"https://foo.bar/image.jpg"}}],"actor_id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606","actor_type":"agent"}],"channel_id":"0534f78-b6e9-4f79-8853-11cedfc1f35b","users":[{"id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606"}]}`, + ExpectedStatus: "W", + ExpectedExternalID: "", SendPrep: setSendURL, }, } diff --git a/handlers/test.go b/handlers/test.go index e8127d384..492be634e 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -4,7 +4,7 @@ import ( "bytes" "context" "encoding/json" - "io/ioutil" + "io" "mime/multipart" "net/http" "net/http/httptest" @@ -70,6 +70,10 @@ type MockedRequest struct { BodyContains string } +func (m MockedRequest) Matches(r *http.Request, body []byte) bool { + return m.Method == r.Method && m.Path == r.URL.Path && m.RawQuery == r.URL.RawQuery && (m.Body == string(body) || (m.BodyContains != "" && strings.Contains(string(body), m.BodyContains))) +} + // ChannelSendTestCase defines the test values for a particular test case type ChannelSendTestCase struct { Label string @@ -172,8 +176,8 @@ func testHandlerRequest(tb testing.TB, s courier.Server, path string, headers ma func newServer(backend courier.Backend) courier.Server { // for benchmarks, log to null logger := logrus.New() - logger.Out = ioutil.Discard - logrus.SetOutput(ioutil.Discard) + logger.Out = io.Discard + logrus.SetOutput(io.Discard) config := courier.NewConfig() config.FacebookWebhookSecret = "fb_webhook_secret" @@ -196,6 +200,7 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour for _, tc := range testCases { mockRRCount := 0 + t.Run(tc.Label, func(t *testing.T) { require := require.New(t) @@ -216,18 +221,16 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour var testRequest *http.Request server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - body, _ := ioutil.ReadAll(r.Body) + body, _ := io.ReadAll(r.Body) testRequest = httptest.NewRequest(r.Method, r.URL.String(), bytes.NewBuffer(body)) testRequest.Header = r.Header + if (len(tc.MockResponses)) == 0 { w.WriteHeader(tc.MockResponseStatus) w.Write([]byte(tc.MockResponseBody)) } else { - require.Zero(tc.MockResponseStatus, "ResponseStatus should not be used when using testcase.Responses") - require.Zero(tc.MockResponseBody, "ResponseBody should not be used when using testcase.Responses") for mockRequest, mockResponse := range tc.MockResponses { - bodyStr := string(body)[:] - if mockRequest.Method == r.Method && mockRequest.Path == r.URL.Path && mockRequest.RawQuery == r.URL.RawQuery && (mockRequest.Body == bodyStr || (mockRequest.BodyContains != "" && strings.Contains(bodyStr, mockRequest.BodyContains))) { + if mockRequest == (MockedRequest{}) || mockRequest.Matches(r, body) { w.WriteHeader(mockResponse.Status) w.Write(mockResponse.Body) mockRRCount++ @@ -279,7 +282,7 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour if tc.ExpectedRequestBody != "" { require.NotNil(testRequest, "request body should not be nil") - value, _ := ioutil.ReadAll(testRequest.Body) + value, _ := io.ReadAll(testRequest.Body) require.Equal(tc.ExpectedRequestBody, strings.Trim(string(value), "\n")) } From eb86d465aed847f74ecb14c4320b432862224f6c Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Sat, 13 Aug 2022 08:36:07 +0200 Subject: [PATCH 071/294] Line should only work for attachments with Media objects, update comments --- handlers/line/line.go | 8 ++++---- handlers/line/line_test.go | 9 ++++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/handlers/line/line.go b/handlers/line/line.go index 1e8dc0994..5e21dd9fc 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -32,10 +32,10 @@ var ( signatureHeader = "X-Line-Signature" ) -// see https://core.telegram.org/bots/api#sending-files +// see https://developers.line.biz/en/reference/messaging-api/#message-objects var mediaSupport = map[handlers.MediaType]handlers.MediaTypeSupport{ - handlers.MediaTypeImage: {Types: []string{"image/jpe", "image/jpg", "image/jpeg", "image/png"}, MaxBytes: 10 * 1024 * 1024}, - handlers.MediaTypeAudio: {Types: []string{"audio/mp4", "audio/m4a"}, MaxBytes: 200 * 1024 * 1024}, + handlers.MediaTypeImage: {Types: []string{"image/jpeg", "image/png"}, MaxBytes: 10 * 1024 * 1024}, + handlers.MediaTypeAudio: {Types: []string{"audio/mp4"}, MaxBytes: 200 * 1024 * 1024}, handlers.MediaTypeVideo: {Types: []string{"video/mp4"}, MaxBytes: 200 * 1024 * 1024}, handlers.MediaTypeApplication: {}, } @@ -321,7 +321,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } } - attachments, err := handlers.ResolveAttachments(ctx, h.Backend(), msg.Attachments(), mediaSupport, true) + attachments, err := handlers.ResolveAttachments(ctx, h.Backend(), msg.Attachments(), mediaSupport, false) if err != nil { return nil, errors.Wrap(err, "error resolving attachments") } diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index 293d16ce3..09fa2797f 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -395,7 +395,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My pic!"},{"type":"image","originalContentUrl":"http://mock.com/1234/test.jpg","previewImageUrl":"http://mock.com/1234/test.jpg"}]}`, SendPrep: setSendURL}, {Label: "Send Other Attachment", - MsgText: "My doc!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, + MsgText: "My doc!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"application/pdf:http://mock.com/7890/test.pdf"}, ExpectedStatus: "W", MockResponseBody: `{}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -403,7 +403,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Accept": "application/json", "Authorization": "Bearer AccessToken", }, - ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My doc!"},{"type":"text","text":"https://foo.bar/document.pdf"}]}`, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My doc!"},{"type":"text","text":"http://mock.com/7890/test.pdf"}]}`, SendPrep: setSendURL}, {Label: "Send Message Batches", MsgText: tooLongMsg, @@ -470,7 +470,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL}, } -// setSendURL takes care of setting the base_url to our test server host +// setupMedia takes care of having the media files needed to our test server host func setupMedia(mb *test.MockBackend) { imageJPG := test.NewMockMedia("test.jpg", "image/jpeg", "http://mock.com/1234/test.jpg", 1024*1024, 640, 480, 0, nil) @@ -482,10 +482,13 @@ func setupMedia(mb *test.MockBackend) { videoMOV := test.NewMockMedia("test.mov", "video/quicktime", "http://mock.com/6789/test.mov", 100*1024*1024, 0, 0, 2000, nil) + filePDF := test.NewMockMedia("test.pdf", "application/pdf", "http://mock.com/7890/test.pdf", 100*1024*1024, 0, 0, 0, nil) + mb.MockMedia(imageJPG) mb.MockMedia(audioMP3) mb.MockMedia(videoMP4) mb.MockMedia(videoMOV) + mb.MockMedia(filePDF) } func TestSending(t *testing.T) { From 90e4c03e5bece7fdfa0673345b4409079bffdb0e Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 15 Aug 2022 09:21:42 -0500 Subject: [PATCH 072/294] Update CHANGELOG.md for v7.5.10 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cbae67f32..dcd0fbad2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +v7.5.10 +---------- + * Update to latest gocommon and fix some go warnings + * Support media attachments for LINE + * Rework handler DescribeURN methods to take a channel logger + * Update more sending to use channel logger + v7.5.9 ---------- * Rename S3MediaBucket to S3AttachmentsBucket and S3MediaPrefix to S3AttachmentsPrefix From e35e38578fff5d4025032d33d95db65bb00b7425 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 12 Aug 2022 16:26:05 -0500 Subject: [PATCH 073/294] Rework more channel types to pass back traces and errors via logger instead of on status object --- handlers/facebook/facebook.go | 30 ++- handlers/facebook/facebook_test.go | 1 + handlers/facebookapp/facebookapp.go | 48 ++--- handlers/facebookapp/facebookapp_test.go | 2 + handlers/freshchat/freshchat.go | 3 +- handlers/kaleyra/kaleyra.go | 45 ++--- handlers/slack/slack.go | 98 +++++----- handlers/slack/slack_test.go | 40 ++-- handlers/telegram/telegram.go | 3 +- handlers/telegram/telegram_test.go | 1 + handlers/test.go | 2 +- handlers/twiml/twiml.go | 24 +-- handlers/twiml/twiml_test.go | 16 ++ handlers/viber/viber.go | 19 +- handlers/viber/viber_test.go | 234 ++++++++++++----------- handlers/vk/vk.go | 22 +-- 16 files changed, 288 insertions(+), 300 deletions(-) diff --git a/handlers/facebook/facebook.go b/handlers/facebook/facebook.go index 92d463412..621038053 100644 --- a/handlers/facebook/facebook.go +++ b/handlers/facebook/facebook.go @@ -555,18 +555,14 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - externalID, err := jsonparser.GetString(trace.ResponseBody, "message_id") + externalID, err := jsonparser.GetString(respBody, "message_id") if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to get message_id from body")) + logger.Error(errors.Errorf("unable to get message_id from body")) return status, nil } @@ -574,9 +570,9 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha if i == 0 { status.SetExternalID(externalID) if msg.URN().IsFacebookRef() { - recipientID, err := jsonparser.GetString(trace.ResponseBody, "recipient_id") + recipientID, err := jsonparser.GetString(respBody, "recipient_id") if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to get recipient_id from body")) + logger.Error(errors.Errorf("unable to get recipient_id from body")) return status, nil } @@ -584,33 +580,31 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha realIDURN, err := urns.NewFacebookURN(recipientID) if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to make facebook urn from %s", recipientID)) + logger.Error(errors.Errorf("unable to make facebook urn from %s", recipientID)) } contact, err := h.Backend().GetContact(ctx, msg.Channel(), msg.URN(), "", "") if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to get contact for %s", msg.URN().String())) + logger.Error(errors.Errorf("unable to get contact for %s", msg.URN().String())) } realURN, err := h.Backend().AddURNtoContact(ctx, msg.Channel(), contact, realIDURN) if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to add real facebook URN %s to contact with uuid %s", realURN.String(), contact.UUID())) + logger.Error(errors.Errorf("unable to add real facebook URN %s to contact with uuid %s", realURN.String(), contact.UUID())) } referralIDExtURN, err := urns.NewURNFromParts(urns.ExternalScheme, referralID, "", "") if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to make ext urn from %s", referralID)) + logger.Error(errors.Errorf("unable to make ext urn from %s", referralID)) } extURN, err := h.Backend().AddURNtoContact(ctx, msg.Channel(), contact, referralIDExtURN) if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to add URN %s to contact with uuid %s", extURN.String(), contact.UUID())) + logger.Error(errors.Errorf("unable to add URN %s to contact with uuid %s", extURN.String(), contact.UUID())) } referralFacebookURN, err := h.Backend().RemoveURNfromContact(ctx, msg.Channel(), contact, msg.URN()) if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to remove referral facebook URN %s from contact with uuid %s", referralFacebookURN.String(), contact.UUID())) + logger.Error(errors.Errorf("unable to remove referral facebook URN %s from contact with uuid %s", referralFacebookURN.String(), contact.UUID())) } - } - } // this was wired successfully diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index da1094dcd..bf6abe798 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -670,6 +670,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get message_id from body"}, SendPrep: setSendURL, }, { diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 79b92cfc6..0b8c85134 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -805,15 +805,15 @@ type mtQuickReply struct { func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { if msg.Channel().ChannelType() == "FBA" || msg.Channel().ChannelType() == "IG" { - return h.sendFacebookInstagramMsg(ctx, msg) + return h.sendFacebookInstagramMsg(ctx, msg, logger) } else if msg.Channel().ChannelType() == "WAC" { - return h.sendCloudAPIWhatsappMsg(ctx, msg) + return h.sendCloudAPIWhatsappMsg(ctx, msg, logger) } return nil, fmt.Errorf("unssuported channel type") } -func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { // can't do anything without an access token accessToken := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if accessToken == "" { @@ -894,18 +894,14 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg) req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - externalID, err := jsonparser.GetString(trace.ResponseBody, "message_id") + externalID, err := jsonparser.GetString(respBody, "message_id") if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to get message_id from body")) + logger.Error(errors.Errorf("unable to get message_id from body")) return status, nil } @@ -913,9 +909,9 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg) if i == 0 { status.SetExternalID(externalID) if msg.URN().IsFacebookRef() { - recipientID, err := jsonparser.GetString(trace.ResponseBody, "recipient_id") + recipientID, err := jsonparser.GetString(respBody, "recipient_id") if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to get recipient_id from body")) + logger.Error(errors.Errorf("unable to get recipient_id from body")) return status, nil } @@ -923,29 +919,29 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg) realIDURN, err := urns.NewFacebookURN(recipientID) if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to make facebook urn from %s", recipientID)) + logger.Error(errors.Errorf("unable to make facebook urn from %s", recipientID)) } contact, err := h.Backend().GetContact(ctx, msg.Channel(), msg.URN(), "", "") if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to get contact for %s", msg.URN().String())) + logger.Error(errors.Errorf("unable to get contact for %s", msg.URN().String())) } realURN, err := h.Backend().AddURNtoContact(ctx, msg.Channel(), contact, realIDURN) if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to add real facebook URN %s to contact with uuid %s", realURN.String(), contact.UUID())) + logger.Error(errors.Errorf("unable to add real facebook URN %s to contact with uuid %s", realURN.String(), contact.UUID())) } referralIDExtURN, err := urns.NewURNFromParts(urns.ExternalScheme, referralID, "", "") if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to make ext urn from %s", referralID)) + logger.Error(errors.Errorf("unable to make ext urn from %s", referralID)) } extURN, err := h.Backend().AddURNtoContact(ctx, msg.Channel(), contact, referralIDExtURN) if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to add URN %s to contact with uuid %s", extURN.String(), contact.UUID())) + logger.Error(errors.Errorf("unable to add URN %s to contact with uuid %s", extURN.String(), contact.UUID())) } referralFacebookURN, err := h.Backend().RemoveURNfromContact(ctx, msg.Channel(), contact, msg.URN()) if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to remove referral facebook URN %s from contact with uuid %s", referralFacebookURN.String(), contact.UUID())) + logger.Error(errors.Errorf("unable to remove referral facebook URN %s from contact with uuid %s", referralFacebookURN.String(), contact.UUID())) } } @@ -1059,7 +1055,7 @@ type wacMTResponse struct { } `json:"messages"` } -func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { // can't do anything without an access token accessToken := h.Server().Config().WhatsappAdminSystemUserToken @@ -1278,19 +1274,15 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg) req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } respPayload := &wacMTResponse{} - err = json.Unmarshal(trace.ResponseBody, respPayload) + err = json.Unmarshal(respBody, respPayload) if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to unmarshal response body")) + logger.Error(errors.Errorf("unable to unmarshal response body")) return status, nil } externalID := respPayload.Messages[0].ID diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index cccb232fb..09c62d026 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -491,6 +491,7 @@ var SendTestCasesFBA = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get message_id from body"}, SendPrep: setSendURL, }, { @@ -603,6 +604,7 @@ var SendTestCasesIG = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get message_id from body"}, SendPrep: setSendURL, }, { diff --git a/handlers/freshchat/freshchat.go b/handlers/freshchat/freshchat.go index 2e8a8a807..8ffade2a4 100644 --- a/handlers/freshchat/freshchat.go +++ b/handlers/freshchat/freshchat.go @@ -148,8 +148,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha msgimage.Image = &Image{URL: mediaURL} payload.Messages[0].MessageParts = append(payload.Messages[0].MessageParts, *msgimage) default: - status.AddLog(courier.NewChannelLogFromError("Unknown media type: "+mediaType, msg.Channel(), msg.ID(), - time.Duration(0), fmt.Errorf("unknown media type: %s", mediaType))) + logger.Error(fmt.Errorf("unknown media type: %s", mediaType)) } } diff --git a/handlers/kaleyra/kaleyra.go b/handlers/kaleyra/kaleyra.go index be276ee14..3111c3230 100644 --- a/handlers/kaleyra/kaleyra.go +++ b/handlers/kaleyra/kaleyra.go @@ -16,7 +16,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/urns" "github.com/pkg/errors" ) @@ -139,7 +138,6 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w // Send sends the given message, logging any HTTP calls or errors func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { - start := time.Now() accountSID := msg.Channel().StringConfigForKey(configAccountSID, "") apiKey := msg.Channel().StringConfigForKey(configApiKey, "") @@ -150,8 +148,8 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) sendURL := fmt.Sprintf("%s/v1/%s/messages", baseURL, accountSID) - var logs []*courier.ChannelLog - var kwaRes *httpx.Trace + var kwaResp *http.Response + var kwaRespBody []byte var kwaErr error // make multipart form requests if we have attachments, the kaleyra api doesn't supports media url nor media upload before send @@ -162,11 +160,9 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha // download media req, _ := http.NewRequest(http.MethodGet, attachmentURL, nil) - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - log := courier.NewChannelLogFromTrace("Media Fetch", msg.Channel(), msg.ID(), trace) - logs = append(logs, log) - kwaErr = err + resp, attBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + kwaErr = errors.New("unable to fetch media") break } @@ -176,11 +172,9 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha body := &bytes.Buffer{} writer := multipart.NewWriter(body) part, err := writer.CreateFormFile("media", fileName) - _, err = io.Copy(part, bytes.NewReader(trace.ResponseBody)) + _, err = io.Copy(part, bytes.NewReader(attBody)) if err != nil { - elapsed := time.Now().Sub(start) - log := courier.NewChannelLogFromError("Media Send APPEND media Field Error", msg.Channel(), msg.ID(), elapsed, err) - logs = append(logs, log) + logger.Error(err) kwaErr = err break } @@ -193,18 +187,14 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha for k, v := range baseForm { part, err := writer.CreateFormField(k) if err != nil { - elapsed := time.Now().Sub(start) - log := courier.NewChannelLogFromError(fmt.Sprintf("Media Send APPEND %s Field Error", k), msg.Channel(), msg.ID(), elapsed, err) - logs = append(logs, log) + logger.Error(err) kwaErr = err break attachmentsLoop } _, err = part.Write([]byte(v)) if err != nil { - elapsed := time.Now().Sub(start) - log := courier.NewChannelLogFromError(fmt.Sprintf("Media Send APPEND %s Field Error", k), msg.Channel(), msg.ID(), elapsed, err) - logs = append(logs, log) + logger.Error(err) kwaErr = err break attachmentsLoop } @@ -215,7 +205,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha // send multipart form req, _ = http.NewRequest(http.MethodPost, sendURL, body) req.Header.Set("Content-Type", writer.FormDataContentType()) - kwaRes, kwaErr = handlers.MakeHTTPRequest(req) + kwaResp, kwaRespBody, kwaErr = handlers.RequestHTTP(req, logger) } } else { form := url.Values{} @@ -231,25 +221,16 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req, _ := http.NewRequest(http.MethodPost, sendURL, strings.NewReader(form.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - kwaRes, kwaErr = handlers.MakeHTTPRequest(req) - } - - if kwaRes != nil { - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), kwaRes).WithError("Message Send Error", kwaErr) - logs = append(logs, log) - } - // add logs to status - for _, log := range logs { - status.AddLog(log) + kwaResp, kwaRespBody, kwaErr = handlers.RequestHTTP(req, logger) } - if kwaErr != nil { + if kwaErr != nil || kwaResp.StatusCode/100 != 2 { status.SetStatus(courier.MsgFailed) return status, nil } // record external id from the last sent msg request - externalID, err := jsonparser.GetString(kwaRes.ResponseBody, "id") + externalID, err := jsonparser.GetString(kwaRespBody, "id") if err == nil { status.SetExternalID(externalID) } diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index 207f498eb..c3bd2ec76 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -158,34 +158,35 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - hasError := true - for _, attachment := range msg.Attachments() { - fileAttachment, log, err := parseAttachmentToFileParams(msg, attachment) - hasError = err != nil - status.AddLog(log) + fileAttachment, err := parseAttachmentToFileParams(msg, attachment, logger) + if err != nil { + logger.Error(err) + return status, nil + } if fileAttachment != nil { - log, err = sendFilePart(msg, botToken, fileAttachment) - hasError = err != nil - status.AddLog(log) + err = sendFilePart(msg, botToken, fileAttachment, logger) + if err != nil { + logger.Error(err) + return status, nil + } } } if msg.Text() != "" { - log, err := sendTextMsgPart(msg, botToken) - hasError = err != nil - status.AddLog(log) - } - - if !hasError { - status.SetStatus(courier.MsgWired) + err := sendTextMsgPart(msg, botToken, logger) + if err != nil { + logger.Error(err) + return status, nil + } } + status.SetStatus(courier.MsgWired) return status, nil } -func sendTextMsgPart(msg courier.Msg, token string) (*courier.ChannelLog, error) { +func sendTextMsgPart(msg courier.Msg, token string, logger *courier.ChannelLogger) error { sendURL := apiURL + "/chat.postMessage" msgPayload := &mtPayload{ @@ -195,77 +196,76 @@ func sendTextMsgPart(msg courier.Msg, token string) (*courier.ChannelLog, error) body, err := json.Marshal(msgPayload) if err != nil { - return nil, err + return err } req, err := http.NewRequest(http.MethodPost, sendURL, bytes.NewReader(body)) if err != nil { - return nil, err + return err } req.Header.Set("Content-Type", "application/json; charset=utf-8") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) - trace, err := handlers.MakeHTTPRequest(req) - - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return errors.New("error sending message") + } - ok, err := jsonparser.GetBoolean(trace.ResponseBody, "ok") + ok, err := jsonparser.GetBoolean(respBody, "ok") if err != nil { - return log, err + return err } if !ok { - errDescription, err := jsonparser.GetString(trace.ResponseBody, "error") + errDescription, err := jsonparser.GetString(respBody, "error") if err != nil { - return log, err + return err } - return log, errors.New(errDescription) + return errors.New(errDescription) } - return log, nil + return nil } -func parseAttachmentToFileParams(msg courier.Msg, attachment string) (*FileParams, *courier.ChannelLog, error) { +func parseAttachmentToFileParams(msg courier.Msg, attachment string, logger *courier.ChannelLogger) (*FileParams, error) { _, attURL := handlers.SplitAttachment(attachment) req, err := http.NewRequest(http.MethodGet, attURL, nil) if err != nil { - return nil, nil, errors.Wrapf(err, "error building file request") + return nil, errors.Wrapf(err, "error building file request") } - trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromTrace("Fetching attachment", msg.Channel(), msg.ID(), trace).WithError("error fetching media", err) + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return nil, errors.New("error fetching attachment") + } filename, err := utils.BasePathForURL(attURL) if err != nil { - return nil, log, err + return nil, err } - return &FileParams{ - File: trace.ResponseBody, - FileName: filename, - Channels: msg.URN().Path(), - }, log, nil + return &FileParams{File: respBody, FileName: filename, Channels: msg.URN().Path()}, nil } -func sendFilePart(msg courier.Msg, token string, fileParams *FileParams) (*courier.ChannelLog, error) { +func sendFilePart(msg courier.Msg, token string, fileParams *FileParams, logger *courier.ChannelLogger) error { uploadURL := apiURL + "/files.upload" body := &bytes.Buffer{} writer := multipart.NewWriter(body) mediaPart, err := writer.CreateFormFile("file", fileParams.FileName) if err != nil { - return nil, errors.Wrapf(err, "failed to create file form field") + return errors.Wrapf(err, "failed to create file form field") } io.Copy(mediaPart, bytes.NewReader(fileParams.File)) filenamePart, err := writer.CreateFormField("filename") if err != nil { - return nil, errors.Wrapf(err, "failed to create filename form field") + return errors.Wrapf(err, "failed to create filename form field") } io.Copy(filenamePart, strings.NewReader(fileParams.FileName)) channelsPart, err := writer.CreateFormField("channels") if err != nil { - return nil, errors.Wrapf(err, "failed to create channels form field") + return errors.Wrapf(err, "failed to create channels form field") } io.Copy(channelsPart, strings.NewReader(fileParams.Channels)) @@ -273,26 +273,26 @@ func sendFilePart(msg courier.Msg, token string, fileParams *FileParams) (*couri req, err := http.NewRequest(http.MethodPost, uploadURL, bytes.NewReader(body.Bytes())) if err != nil { - return nil, errors.Wrapf(err, "error building request to file upload endpoint") + return errors.Wrapf(err, "error building request to file upload endpoint") } req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) req.Header.Add("Content-Type", writer.FormDataContentType()) - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - return nil, errors.Wrapf(err, "error uploading file to slack") + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return errors.New("error uploading file to slack") } var fr FileResponse - if err := json.Unmarshal(trace.ResponseBody, &fr); err != nil { - return nil, errors.Errorf("couldn't unmarshal file response: %v", err) + if err := json.Unmarshal(respBody, &fr); err != nil { + return errors.Errorf("couldn't unmarshal file response: %v", err) } if !fr.OK { - return nil, errors.Errorf("error uploading file to slack: %s.", fr.Error) + return errors.Errorf("error uploading file to slack: %s.", fr.Error) } - return courier.NewChannelLogFromTrace("uploading file to Slack", msg.Channel(), msg.ID(), trace).WithError("Error uploading file to Slack", err), nil + return nil } // DescribeURN handles Slack user details diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 3c30398a6..e88b1b40f 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -179,39 +179,43 @@ var handleTestCases = []ChannelHandleTestCase{ var defaultSendTestCases = []ChannelSendTestCase{ { - Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "slack:U0123ABCDEF", - ExpectedStatus: "W", + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "slack:U0123ABCDEF", MockResponseBody: `{"ok":true,"channel":"U0123ABCDEF"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"channel":"U0123ABCDEF","text":"Simple Message"}`, + ExpectedStatus: "W", SendPrep: setSendUrl, }, { - Label: "Unicode Send", - MsgText: "☺", MsgURN: "slack:U0123ABCDEF", - ExpectedStatus: "W", + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "slack:U0123ABCDEF", MockResponseBody: `{"ok":true,"channel":"U0123ABCDEF"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"channel":"U0123ABCDEF","text":"☺"}`, + ExpectedStatus: "W", SendPrep: setSendUrl, }, { - Label: "Send Text Auth Error", - MsgText: "Hello", MsgURN: "slack:U0123ABCDEF", - ExpectedStatus: "E", + Label: "Send Text Auth Error", + MsgText: "Hello", + MsgURN: "slack:U0123ABCDEF", MockResponseBody: `{"ok":false,"error":"invalid_auth"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"channel":"U0123ABCDEF","text":"Hello"}`, + ExpectedStatus: "E", + ExpectedErrors: []string{"invalid_auth"}, SendPrep: setSendUrl, }, } var fileSendTestCases = []ChannelSendTestCase{ { - Label: "Send Image", - MsgText: "", MsgURN: "slack:U0123ABCDEF", - ExpectedStatus: "W", + Label: "Send Image", + MsgText: "", + MsgURN: "slack:U0123ABCDEF", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.png"}, MockResponses: map[MockedRequest]*httpx.MockResponse{ { @@ -220,12 +224,13 @@ var fileSendTestCases = []ChannelSendTestCase{ BodyContains: "image.png", }: httpx.NewMockResponse(200, nil, []byte(`{"ok":true,"file":{"id":"F1L3SL4CK1D"}}`)), }, - SendPrep: setSendUrl, + ExpectedStatus: "W", + SendPrep: setSendUrl, }, { - Label: "Send Image", - MsgText: "", MsgURN: "slack:U0123ABCDEF", - ExpectedStatus: "W", + Label: "Send Image", + MsgText: "", + MsgURN: "slack:U0123ABCDEF", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.png"}, MockResponses: map[MockedRequest]*httpx.MockResponse{ { @@ -234,7 +239,8 @@ var fileSendTestCases = []ChannelSendTestCase{ BodyContains: "image.png", }: httpx.NewMockResponse(200, nil, []byte(`{"ok":true,"file":{"id":"F1L3SL4CK1D"}}`)), }, - SendPrep: setSendUrl, + ExpectedStatus: "W", + SendPrep: setSendUrl, }, } diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index 2e7be389e..81eaaaee6 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -312,8 +312,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha hasError = err != nil default: - status.AddLog(courier.NewChannelLogFromError("Unknown attachment content type: "+attachment.ContentType, - msg.Channel(), msg.ID(), time.Duration(0), fmt.Errorf("unknown attachment content type: %s", attachment.ContentType))) + logger.Error(fmt.Errorf("unknown attachment content type: %s", attachment.ContentType)) hasError = true } } diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index 4ce3cef2b..2b2244e39 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -712,6 +712,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "telegram:12345", MsgAttachments: []string{"unknown/foo:https://foo.bar/unknown.foo"}, ExpectedStatus: "E", + ExpectedErrors: []string{"unknown attachment content type: unknown/foo"}, SendPrep: setSendURL, }, } diff --git a/handlers/test.go b/handlers/test.go index 492be634e..5be1ba361 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -287,7 +287,7 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour } if (len(tc.MockResponses)) != 0 { - require.Equal(mockRRCount, len(tc.MockResponses)) + assert.Equal(t, len(tc.MockResponses), mockRRCount, "mocked request count mismatch") } if tc.ExpectedHeaders != nil { diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index 658f7c5ec..957bcc477 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -266,15 +266,14 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil { + return status, nil + } // see if we can parse the error if we have one - if err != nil && len(trace.ResponseBody) > 0 { - errorCode, _ := jsonparser.GetInt(trace.ResponseBody, "code") + if resp.StatusCode/100 != 2 && len(respBody) > 0 { + errorCode, _ := jsonparser.GetInt(respBody, "code") if errorCode != 0 { if errorCode == errorStopped { status.SetStatus(courier.MsgFailed) @@ -286,20 +285,15 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return nil, err } } - log.WithError("Message Send Error", errors.Errorf("received error code from twilio '%d'", errorCode)) + logger.Error(errors.Errorf("received error code from twilio '%d'", errorCode)) return status, nil } } - // fail if we received an error - if err != nil { - return status, nil - } - // grab the external id - externalID, err := jsonparser.GetString(trace.ResponseBody, "sid") + externalID, err := jsonparser.GetString(respBody, "sid") if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to get sid from body")) + logger.Error(errors.Errorf("unable to get sid from body")) return status, nil } diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index 051bbac33..1ad905905 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -325,6 +325,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get sid from body"}, SendPrep: setSendURL, }, { @@ -335,6 +336,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get sid from body"}, SendPrep: setSendURL, }, { @@ -346,6 +348,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStopEvent: true, ExpectedStatus: "F", + ExpectedErrors: []string{"received error code from twilio '21610'"}, SendPrep: setSendURL, }, { @@ -356,6 +359,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get sid from body"}, SendPrep: setSendURL, }, { @@ -406,6 +410,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get sid from body"}, SendPrep: setSendURL, }, { @@ -416,6 +421,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get sid from body"}, SendPrep: setSendURL, }, { @@ -427,6 +433,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedStopEvent: true, ExpectedStatus: "F", + ExpectedErrors: []string{"received error code from twilio '21610'"}, SendPrep: setSendURL, }, { @@ -437,6 +444,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get sid from body"}, SendPrep: setSendURL, }, { @@ -487,6 +495,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get sid from body"}, SendPrep: setSendURL, }, { @@ -497,6 +506,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get sid from body"}, SendPrep: setSendURL, }, { @@ -508,6 +518,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "F", ExpectedStopEvent: true, + ExpectedErrors: []string{"received error code from twilio '21610'"}, SendPrep: setSendURL, }, { @@ -518,6 +529,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get sid from body"}, SendPrep: setSendURL, }, { @@ -568,6 +580,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get sid from body"}, SendPrep: setSendURL, }, { @@ -578,6 +591,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get sid from body"}, SendPrep: setSendURL, }, { @@ -589,6 +603,7 @@ var swSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "F", ExpectedStopEvent: true, + ExpectedErrors: []string{"received error code from twilio '21610'"}, SendPrep: setSendURL, }, { @@ -599,6 +614,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", + ExpectedErrors: []string{"unable to get sid from body"}, SendPrep: setSendURL, }, { diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index f220f145f..429dd611c 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -12,7 +12,6 @@ import ( "net/http" "strconv" "strings" - "time" "github.com/buger/jsonparser" "github.com/nyaruka/courier" @@ -376,8 +375,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha msgText = "" default: - status.AddLog(courier.NewChannelLogFromError("Unknown media type: "+mediaType, msg.Channel(), msg.ID(), - time.Duration(0), fmt.Errorf("unknown media type: %s", mediaType))) + logger.Error(fmt.Errorf("unknown media type: %s", mediaType)) } } else { @@ -413,22 +411,17 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequest(req) - - // record log - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { return status, nil } - - responseStatus, err := jsonparser.GetInt(trace.ResponseBody, "status") + responseStatus, err := jsonparser.GetInt(respBody, "status") if err != nil { - log.WithError("Message Send Error", errors.Errorf("received invalid JSON response")) + logger.Error(errors.Errorf("received invalid JSON response")) return status, nil } if responseStatus != 0 { - log.WithError("Message Send Error", errors.Errorf("received non-0 status: '%d'", responseStatus)) + logger.Error(errors.Errorf("received non-0 status: '%d'", responseStatus)) return status, nil } diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index 1fd9eb71a..4a260ff3a 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -45,118 +45,133 @@ func buildMockAttachmentService(testCases []ChannelSendTestCase) *httptest.Serve } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", - ExpectedStatus: "W", MockResponseStatus: 200, - MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - }, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, - {Label: "Long Send", - MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", - ExpectedStatus: "W", MockResponseStatus: 200, - MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - }, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Long Send", + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"I need to keep adding more things to make it work","type":"text","tracking_data":"10"}`, + ExpectedStatus: "W", SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: "☺", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", - ExpectedStatus: "W", MockResponseStatus: 200, - MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - }, + { + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"☺","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, - {Label: "Quick Reply", - MsgText: "Are you happy?", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", MsgQuickReplies: []string{"Yes", "No"}, - ExpectedStatus: "W", MockResponseStatus: 200, - MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - }, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Quick Reply", + MsgText: "Are you happy?", + MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + MsgQuickReplies: []string{"Yes", "No"}, + MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Are you happy?","type":"text","tracking_data":"10","keyboard":{"Type":"keyboard","DefaultHeight":false,"Buttons":[{"ActionType":"reply","ActionBody":"Yes","Text":"Yes","TextSize":"regular","Columns":"3"},{"ActionType":"reply","ActionBody":"No","Text":"No","TextSize":"regular","Columns":"3"}]}}`, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", MsgAttachments: []string{"image/jpeg:https://localhost/image.jpg"}, - ExpectedStatus: "W", MockResponseStatus: 200, - MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - }, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + MsgAttachments: []string{"image/jpeg:https://localhost/image.jpg"}, + MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"My pic!","type":"picture","tracking_data":"10","media":"{{ SERVER_URL }}/image.jpg"}`, - SendPrep: setSendURL}, - {Label: "Long Description with Attachment", - MsgText: "Text description is longer that 10 characters", - MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", MsgAttachments: []string{"image/jpeg:https://localhost/image.jpg"}, - ExpectedStatus: "W", MockResponseStatus: 200, - MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - }, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Long Description with Attachment", + MsgText: "Text description is longer that 10 characters", + MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + MsgAttachments: []string{"image/jpeg:https://localhost/image.jpg"}, + MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Text description is longer that 10 characters","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, - {Label: "Send Attachment Video", - MsgText: "My video!", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", MsgAttachments: []string{"video/mp4:https://localhost/video.mp4"}, - ExpectedStatus: "W", MockResponseStatus: 200, - MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - }, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment Video", + MsgText: "My video!", + MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + MsgAttachments: []string{"video/mp4:https://localhost/video.mp4"}, + MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"My video!","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, - {Label: "Send Attachment Audio", - MsgText: "My audio!", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", MsgAttachments: []string{"audio/mp3:https://localhost/audio.mp3"}, - ExpectedStatus: "W", MockResponseStatus: 200, - MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - }, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment Audio", + MsgText: "My audio!", + MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + MsgAttachments: []string{"audio/mp3:https://localhost/audio.mp3"}, + MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"My audio!","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, - {Label: "Got non-0 response", - MsgText: "Simple Message", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", - ExpectedStatus: "E", MockResponseStatus: 200, - MockResponseBody: `{"status":3,"status_message":"InvalidToken"}`, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - }, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Got non-0 response", + MsgText: "Simple Message", + MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + MockResponseStatus: 200, + MockResponseBody: `{"status":3,"status_message":"InvalidToken"}`, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, - {Label: "Got Invalid JSON response", - MsgText: "Simple Message", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", - ExpectedStatus: "E", MockResponseStatus: 200, - MockResponseBody: `invalidJSON`, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - }, + ExpectedStatus: "E", + ExpectedErrors: []string{"received non-0 status: '3'"}, + SendPrep: setSendURL, + }, + { + Label: "Got Invalid JSON response", + MsgText: "Simple Message", + MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + MockResponseStatus: 200, + MockResponseBody: `invalidJSON`, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", - ExpectedStatus: "E", MockResponseStatus: 401, - MockResponseBody: `{"status":"5"}`, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - }, + ExpectedStatus: "E", + ExpectedErrors: []string{"received invalid JSON response"}, + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + MockResponseStatus: 401, + MockResponseBody: `{"status":"5"}`, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Error Message","type":"text","tracking_data":"10"}`, - SendPrep: setSendURL}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } var invalidTokenSendTestCases = []ChannelSendTestCase{ @@ -167,16 +182,17 @@ var invalidTokenSendTestCases = []ChannelSendTestCase{ } var buttonLayoutSendTestCases = []ChannelSendTestCase{ - {Label: "Quick Reply With Layout With Column, Row and BgColor definitions", - MsgText: "Select a, b, c or d.", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", MsgQuickReplies: []string{"a", "b", "c", "d"}, - ExpectedStatus: "W", MockResponseStatus: 200, - MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - }, + { + Label: "Quick Reply With Layout With Column, Row and BgColor definitions", + MsgText: "Select a, b, c or d.", + MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + MsgQuickReplies: []string{"a", "b", "c", "d"}, + MockResponseStatus: 200, + MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Select a, b, c or d.","type":"text","tracking_data":"10","keyboard":{"Type":"keyboard","DefaultHeight":false,"Buttons":[{"ActionType":"reply","ActionBody":"a","Text":"\u003cfont color=\"#ffffff\"\u003ea\u003c/font\u003e\u003cbr\u003e\u003cbr\u003e","TextSize":"large","Columns":"2","BgColor":"#f7bb3f"},{"ActionType":"reply","ActionBody":"b","Text":"\u003cfont color=\"#ffffff\"\u003eb\u003c/font\u003e\u003cbr\u003e\u003cbr\u003e","TextSize":"large","Columns":"2","BgColor":"#f7bb3f"},{"ActionType":"reply","ActionBody":"c","Text":"\u003cfont color=\"#ffffff\"\u003ec\u003c/font\u003e\u003cbr\u003e\u003cbr\u003e","TextSize":"large","Columns":"2","BgColor":"#f7bb3f"},{"ActionType":"reply","ActionBody":"d","Text":"\u003cfont color=\"#ffffff\"\u003ed\u003c/font\u003e\u003cbr\u003e\u003cbr\u003e","TextSize":"large","Columns":"6","BgColor":"#f7bb3f"}]}}`, - SendPrep: setSendURL}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/vk/vk.go b/handlers/vk/vk.go index a10cc9e52..3a0830940 100644 --- a/handlers/vk/vk.go +++ b/handlers/vk/vk.go @@ -393,7 +393,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha params.Set(paramUserId, msg.URN().Path()) params.Set(paramRandomId, msg.ID().String()) - text, attachments := buildTextAndAttachmentParams(msg, status) + text, attachments := buildTextAndAttachmentParams(msg, logger) params.Set(paramMessage, text) params.Set(paramAttachments, attachments) @@ -411,15 +411,12 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.URL.RawQuery = params.Encode() - trace, err := handlers.MakeHTTPRequest(req) - - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - status.AddLog(log) - - if err != nil { - return status, err + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return status, nil } - externalMsgId, err := jsonparser.GetInt(trace.ResponseBody, responseOutgoingMessageKey) + + externalMsgId, err := jsonparser.GetInt(respBody, responseOutgoingMessageKey) if err != nil { return status, errors.Errorf("no '%s' value in response", responseOutgoingMessageKey) @@ -431,14 +428,13 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } // buildTextAndAttachmentParams builds msg text with attachment links (if needed) and attachments list param, also returns the errors that occurred -func buildTextAndAttachmentParams(msg courier.Msg, status courier.MsgStatus) (string, string) { +func buildTextAndAttachmentParams(msg courier.Msg, logger *courier.ChannelLogger) (string, string) { var msgAttachments []string textBuf := bytes.Buffer{} textBuf.WriteString(msg.Text()) for _, attachment := range msg.Attachments() { - start := time.Now() // handle attachment type mediaPrefix, mediaURL := handlers.SplitAttachment(attachment) mediaPrefixParts := strings.Split(mediaPrefix, "/") @@ -453,9 +449,7 @@ func buildTextAndAttachmentParams(msg courier.Msg, status courier.MsgStatus) (st if attachment, err := handleMediaUploadAndGetAttachment(msg.Channel(), mediaTypeImage, mediaExt, mediaURL); err == nil { msgAttachments = append(msgAttachments, attachment) } else { - duration := time.Now().Sub(start) - log := courier.NewChannelLogFromError("Unable to upload photo attachment", msg.Channel(), msg.ID(), duration, err) - status.AddLog(log) + logger.Error(err) } default: From 4d6bc753d095768da5e369a6002df994794d26f5 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 16 Aug 2022 09:33:37 -0500 Subject: [PATCH 074/294] Update CHANGELOG.md for v7.5.11 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dcd0fbad2..89aeb78bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.11 +---------- + * Rework more channel types to pass back traces and errors via logger instead of on status object + v7.5.10 ---------- * Update to latest gocommon and fix some go warnings From ede845ec603172f95f9daba7ec4a5aa7810d1a15 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Tue, 16 Aug 2022 18:40:16 +0200 Subject: [PATCH 075/294] Adjust to support sending attachments with quick replies later --- handlers/line/line.go | 49 +++++++++++++++++++------------------- handlers/line/line_test.go | 21 ++++++++++++---- 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/handlers/line/line.go b/handlers/line/line.go index 5e21dd9fc..3149fd96d 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -297,30 +297,6 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha parts := handlers.SplitMsgByChannel(msg.Channel(), msg.Text(), maxMsgLength) qrs := msg.QuickReplies() - // fill all msg parts with text parts - for i, part := range parts { - if i < (len(parts) - 1) { - if jsonMsg, err := json.Marshal(mtTextMsg{Type: "text", Text: part}); err == nil { - jsonMsgs = append(jsonMsgs, string(jsonMsg)) - } - } else { - mtTextMsg := mtTextMsg{Type: "text", Text: part} - items := make([]QuickReplyItem, len(qrs)) - for j, qr := range qrs { - items[j] = QuickReplyItem{Type: "action"} - items[j].Action.Type = "message" - items[j].Action.Label = qr - items[j].Action.Text = qr - } - if len(items) > 0 { - mtTextMsg.QuickReply = &mtQuickReply{Items: items} - } - if jsonMsg, err := json.Marshal(mtTextMsg); err == nil { - jsonMsgs = append(jsonMsgs, string(jsonMsg)) - } - } - } - attachments, err := handlers.ResolveAttachments(ctx, h.Backend(), msg.Attachments(), mediaSupport, false) if err != nil { return nil, errors.Wrap(err, "error resolving attachments") @@ -347,6 +323,31 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha jsonMsgs = append(jsonMsgs, string(jsonMsg)) } } + + // fill all msg parts with text parts + for i, part := range parts { + if i < (len(parts) - 1) { + if jsonMsg, err := json.Marshal(mtTextMsg{Type: "text", Text: part}); err == nil { + jsonMsgs = append(jsonMsgs, string(jsonMsg)) + } + } else { + mtTextMsg := mtTextMsg{Type: "text", Text: part} + items := make([]QuickReplyItem, len(qrs)) + for j, qr := range qrs { + items[j] = QuickReplyItem{Type: "action"} + items[j].Action.Type = "message" + items[j].Action.Label = qr + items[j].Action.Text = qr + } + if len(items) > 0 { + mtTextMsg.QuickReply = &mtQuickReply{Items: items} + } + if jsonMsg, err := json.Marshal(mtTextMsg); err == nil { + jsonMsgs = append(jsonMsgs, string(jsonMsg)) + } + } + } + // send msg parts in batches var batch []string batchCount := 0 diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index 93c0f9e7f..08f791221 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -370,7 +370,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Accept": "application/json", "Authorization": "Bearer AccessToken", }, - ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My Audio!"},{"type":"audio","originalContentUrl":"http://mock.com/2345/test.m4a","duration":200}]}`, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"audio","originalContentUrl":"http://mock.com/2345/test.m4a","duration":200},{"type":"text","text":"My Audio!"}]}`, SendPrep: setSendURL}, {Label: "Send Video Attachment", MsgText: "My Video!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"video/mp4:http://mock.com/5678/test.mp4"}, @@ -381,7 +381,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Accept": "application/json", "Authorization": "Bearer AccessToken", }, - ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My Video!"},{"type":"video","originalContentUrl":"http://mock.com/5678/test.mp4","previewImageUrl":"http://mock.com/4567/test.jpg"}]}`, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"video","originalContentUrl":"http://mock.com/5678/test.mp4","previewImageUrl":"http://mock.com/4567/test.jpg"},{"type":"text","text":"My Video!"}]}`, SendPrep: setSendURL}, {Label: "Send Image Attachment", @@ -393,7 +393,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Accept": "application/json", "Authorization": "Bearer AccessToken", }, - ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My pic!"},{"type":"image","originalContentUrl":"http://mock.com/1234/test.jpg","previewImageUrl":"http://mock.com/1234/test.jpg"}]}`, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"image","originalContentUrl":"http://mock.com/1234/test.jpg","previewImageUrl":"http://mock.com/1234/test.jpg"},{"type":"text","text":"My pic!"}]}`, SendPrep: setSendURL}, {Label: "Send Other Attachment", MsgText: "My doc!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"application/pdf:http://mock.com/7890/test.pdf"}, @@ -404,7 +404,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Accept": "application/json", "Authorization": "Bearer AccessToken", }, - ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"My doc!"},{"type":"text","text":"http://mock.com/7890/test.pdf"}]}`, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"http://mock.com/7890/test.pdf"},{"type":"text","text":"My doc!"}]}`, SendPrep: setSendURL}, {Label: "Send Message Batches", MsgText: tooLongMsg, @@ -441,6 +441,19 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Are you happy?","quickReply":{"items":[{"type":"action","action":{"type":"message","label":"Yes","text":"Yes"}},{"type":"action","action":{"type":"message","label":"No","text":"No"}}]}}]}`, SendPrep: setSendURL}, + {Label: "Quick Reply combined and attachment", + MsgText: "Are you happy?", MsgURN: "line:uabcdefghij", + MsgAttachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, + MsgQuickReplies: []string{"Yes", "No"}, + ExpectedStatus: "W", + MockResponseBody: `{}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "Bearer AccessToken", + }, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"image","originalContentUrl":"http://mock.com/1234/test.jpg","previewImageUrl":"http://mock.com/1234/test.jpg"},{"type":"text","text":"Are you happy?","quickReply":{"items":[{"type":"action","action":{"type":"message","label":"Yes","text":"Yes"}},{"type":"action","action":{"type":"message","label":"No","text":"No"}}]}}]}`, + SendPrep: setSendURL}, {Label: "Send Push Message If Invalid Reply", MsgText: "Simple Message", MsgURN: "line:uabcdefghij", MsgResponseToExternalID: "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA", ExpectedStatus: "W", From b232e142577e26eb9471ca24d8cbd255f8b606bb Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 16 Aug 2022 11:52:55 -0500 Subject: [PATCH 076/294] Tidy tests --- handlers/line/line_test.go | 245 +++++++++++++++++++------------------ 1 file changed, 128 insertions(+), 117 deletions(-) diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index 08f791221..f5b6a239a 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -327,136 +327,143 @@ Vivamus justo dolor, gravida at quam eu, hendrerit rutrum justo. Sed hendrerit n Proin vulputate id justo non aliquet.` var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "line:uabcdefghij", - ExpectedStatus: "W", - MockResponseBody: `{}`, MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Bearer AccessToken", - }, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "line:uabcdefghij", + MockResponseBody: `{}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Simple Message"}]}`, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: "Simple Message ☺", MsgURN: "line:uabcdefghij", - ExpectedStatus: "W", - MockResponseBody: `{}`, MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Bearer AccessToken", - }, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "Simple Message ☺", + MsgURN: "line:uabcdefghij", + MockResponseBody: `{}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Simple Message ☺"}]}`, - SendPrep: setSendURL}, - {Label: "Long Send", - MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - MsgURN: "line:uabcdefghij", - ExpectedStatus: "W", - MockResponseBody: `{}`, MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Bearer AccessToken", - }, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Long Send", + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "line:uabcdefghij", + MockResponseBody: `{}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say,"},{"type":"text","text":"I need to keep adding more things to make it work"}]}`, - SendPrep: setSendURL}, - {Label: "Send Audio Attachment", - MsgText: "My Audio!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"audio/mp3:http://mock.com/3456/test.mp3"}, - ExpectedStatus: "W", - MockResponseBody: `{}`, MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Bearer AccessToken", - }, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Audio Attachment", + MsgText: "My Audio!", + MsgURN: "line:uabcdefghij", + MsgAttachments: []string{"audio/mp3:http://mock.com/3456/test.mp3"}, + MockResponseBody: `{}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"audio","originalContentUrl":"http://mock.com/2345/test.m4a","duration":200},{"type":"text","text":"My Audio!"}]}`, - SendPrep: setSendURL}, - {Label: "Send Video Attachment", - MsgText: "My Video!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"video/mp4:http://mock.com/5678/test.mp4"}, - ExpectedStatus: "W", - MockResponseBody: `{}`, MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Bearer AccessToken", - }, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Video Attachment", + MsgText: "My Video!", + MsgURN: "line:uabcdefghij", + MsgAttachments: []string{"video/mp4:http://mock.com/5678/test.mp4"}, + MockResponseBody: `{}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"video","originalContentUrl":"http://mock.com/5678/test.mp4","previewImageUrl":"http://mock.com/4567/test.jpg"},{"type":"text","text":"My Video!"}]}`, - SendPrep: setSendURL}, - - {Label: "Send Image Attachment", - MsgText: "My pic!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, - ExpectedStatus: "W", - MockResponseBody: `{}`, MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Bearer AccessToken", - }, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + + { + Label: "Send Image Attachment", + MsgText: "My pic!", + MsgURN: "line:uabcdefghij", + MsgAttachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, + MockResponseBody: `{}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"image","originalContentUrl":"http://mock.com/1234/test.jpg","previewImageUrl":"http://mock.com/1234/test.jpg"},{"type":"text","text":"My pic!"}]}`, - SendPrep: setSendURL}, - {Label: "Send Other Attachment", - MsgText: "My doc!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"application/pdf:http://mock.com/7890/test.pdf"}, - ExpectedStatus: "W", - MockResponseBody: `{}`, MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Bearer AccessToken", - }, - ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"http://mock.com/7890/test.pdf"},{"type":"text","text":"My doc!"}]}`, - SendPrep: setSendURL}, - {Label: "Send Message Batches", - MsgText: tooLongMsg, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Other Attachment", + MsgText: "My doc!", MsgURN: "line:uabcdefghij", + MsgAttachments: []string{"application/pdf:http://mock.com/7890/test.pdf"}, ExpectedStatus: "W", MockResponseBody: `{}`, MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"http://mock.com/7890/test.pdf"},{"type":"text","text":"My doc!"}]}`, + SendPrep: setSendURL, + }, + { + Label: "Send Message Batches", + MsgText: tooLongMsg, + MsgURN: "line:uabcdefghij", + MockResponseBody: `{}`, + MockResponseStatus: 200, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken", }, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Sed hendrerit nisi vitae nisl ornare tristique.\nProin vulputate id justo non aliquet."}]}`, - SendPrep: setSendURL}, - {Label: "Send Reply Message", - MsgText: "Simple Message", MsgURN: "line:uabcdefghij", MsgResponseToExternalID: "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA", - ExpectedStatus: "W", - MockResponseBody: `{}`, MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Bearer AccessToken", - }, - ExpectedRequestBody: `{"replyToken":"nHuyWiB7yP5Zw52FIkcQobQuGDXCTA","messages":[{"type":"text","text":"Simple Message"}]}`, - SendPrep: setSendURL}, - {Label: "Quick Reply", - MsgText: "Are you happy?", MsgURN: "line:uabcdefghij", - MsgQuickReplies: []string{"Yes", "No"}, - ExpectedStatus: "W", - MockResponseBody: `{}`, MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Bearer AccessToken", - }, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Reply Message", + MsgText: "Simple Message", + MsgURN: "line:uabcdefghij", + MsgResponseToExternalID: "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA", + MockResponseBody: `{}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, + ExpectedRequestBody: `{"replyToken":"nHuyWiB7yP5Zw52FIkcQobQuGDXCTA","messages":[{"type":"text","text":"Simple Message"}]}`, + ExpectedStatus: "W", + SendPrep: setSendURL}, + { + Label: "Quick Reply", + MsgText: "Are you happy?", + MsgURN: "line:uabcdefghij", + MsgQuickReplies: []string{"Yes", "No"}, + MockResponseBody: `{}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Are you happy?","quickReply":{"items":[{"type":"action","action":{"type":"message","label":"Yes","text":"Yes"}},{"type":"action","action":{"type":"message","label":"No","text":"No"}}]}}]}`, - SendPrep: setSendURL}, - {Label: "Quick Reply combined and attachment", - MsgText: "Are you happy?", MsgURN: "line:uabcdefghij", - MsgAttachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, - MsgQuickReplies: []string{"Yes", "No"}, - ExpectedStatus: "W", - MockResponseBody: `{}`, MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Bearer AccessToken", - }, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Quick Reply combined and attachment", + MsgText: "Are you happy?", + MsgURN: "line:uabcdefghij", + MsgAttachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, + MsgQuickReplies: []string{"Yes", "No"}, + MockResponseBody: `{}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"image","originalContentUrl":"http://mock.com/1234/test.jpg","previewImageUrl":"http://mock.com/1234/test.jpg"},{"type":"text","text":"Are you happy?","quickReply":{"items":[{"type":"action","action":{"type":"message","label":"Yes","text":"Yes"}},{"type":"action","action":{"type":"message","label":"No","text":"No"}}]}}]}`, - SendPrep: setSendURL}, - {Label: "Send Push Message If Invalid Reply", - MsgText: "Simple Message", MsgURN: "line:uabcdefghij", MsgResponseToExternalID: "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA", - ExpectedStatus: "W", + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Push Message If Invalid Reply", + MsgText: "Simple Message", + MsgURN: "line:uabcdefghij", + MsgResponseToExternalID: "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA", MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", @@ -469,13 +476,17 @@ var defaultSendTestCases = []ChannelSendTestCase{ BodyContains: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Simple Message"}]}`, }: httpx.NewMockResponse(200, nil, []byte(`{}`)), }, - SendPrep: setSendURL}, - {Label: "Error Sending", + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", MsgText: "Error Sending", MsgURN: "line:uabcdefghij", - ExpectedStatus: "E", MockResponseBody: `{"message": "Error"}`, MockResponseStatus: 403, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Error Sending"}]}`, - SendPrep: setSendURL}, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } // setupMedia takes care of having the media files needed to our test server host From ab4e2b5774f9f27a40c22e11aaf886a44bdcac77 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 16 Aug 2022 11:54:08 -0500 Subject: [PATCH 077/294] Tidy tests --- handlers/line/line_test.go | 40 +++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index f5b6a239a..cfa984e9d 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -398,27 +398,24 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL, }, { - Label: "Send Other Attachment", - MsgText: "My doc!", - MsgURN: "line:uabcdefghij", - MsgAttachments: []string{"application/pdf:http://mock.com/7890/test.pdf"}, - ExpectedStatus: "W", - MockResponseBody: `{}`, MockResponseStatus: 200, + Label: "Send Other Attachment", + MsgText: "My doc!", + MsgURN: "line:uabcdefghij", + MsgAttachments: []string{"application/pdf:http://mock.com/7890/test.pdf"}, + ExpectedStatus: "W", + MockResponseBody: `{}`, + MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"http://mock.com/7890/test.pdf"},{"type":"text","text":"My doc!"}]}`, SendPrep: setSendURL, }, { - Label: "Send Message Batches", - MsgText: tooLongMsg, - MsgURN: "line:uabcdefghij", - MockResponseBody: `{}`, - MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Bearer AccessToken", - }, + Label: "Send Message Batches", + MsgText: tooLongMsg, + MsgURN: "line:uabcdefghij", + MockResponseBody: `{}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Sed hendrerit nisi vitae nisl ornare tristique.\nProin vulputate id justo non aliquet."}]}`, ExpectedStatus: "W", SendPrep: setSendURL, @@ -433,7 +430,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"replyToken":"nHuyWiB7yP5Zw52FIkcQobQuGDXCTA","messages":[{"type":"text","text":"Simple Message"}]}`, ExpectedStatus: "W", - SendPrep: setSendURL}, + SendPrep: setSendURL, + }, { Label: "Quick Reply", MsgText: "Are you happy?", @@ -480,9 +478,11 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL, }, { - Label: "Error Sending", - MsgText: "Error Sending", MsgURN: "line:uabcdefghij", - MockResponseBody: `{"message": "Error"}`, MockResponseStatus: 403, + Label: "Error Sending", + MsgText: "Error Sending", + MsgURN: "line:uabcdefghij", + MockResponseBody: `{"message": "Error"}`, + MockResponseStatus: 403, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Error Sending"}]}`, ExpectedStatus: "E", SendPrep: setSendURL, From 7715eeb87c680f81098f29a29030203179f63e2c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 16 Aug 2022 11:56:54 -0500 Subject: [PATCH 078/294] Update CHANGELOG.md for v7.5.12 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89aeb78bf..baf62ce64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.12 +---------- + * Adjust LINE to support sending attachments with quick replies later + v7.5.11 ---------- * Rework more channel types to pass back traces and errors via logger instead of on status object From 9edf07960c4f8bc2a99c78153dabda2c52133c89 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 17 Aug 2022 14:57:09 -0500 Subject: [PATCH 079/294] Rework WhatsApp handler to use logger, remove code for storing logs on status objects --- backends/rapidpro/status.go | 5 - handlers/whatsapp/whatsapp.go | 196 ++++++++++++++-------------------- sender.go | 5 - status.go | 3 - test/status.go | 3 - 5 files changed, 79 insertions(+), 133 deletions(-) diff --git a/backends/rapidpro/status.go b/backends/rapidpro/status.go index 56759fcf2..3a1517fc3 100644 --- a/backends/rapidpro/status.go +++ b/backends/rapidpro/status.go @@ -320,8 +320,6 @@ type DBMsgStatus struct { ExternalID_ string `json:"external_id,omitempty" db:"external_id"` Status_ courier.MsgStatusValue `json:"status" db:"status"` ModifiedOn_ time.Time `json:"modified_on" db:"modified_on"` - - logs []*courier.ChannelLog } func (s *DBMsgStatus) EventID() int64 { return int64(s.ID_) } @@ -368,8 +366,5 @@ func (s *DBMsgStatus) HasUpdatedURN() bool { func (s *DBMsgStatus) ExternalID() string { return s.ExternalID_ } func (s *DBMsgStatus) SetExternalID(id string) { s.ExternalID_ = id } -func (s *DBMsgStatus) Logs() []*courier.ChannelLog { return s.logs } -func (s *DBMsgStatus) AddLog(log *courier.ChannelLog) { s.logs = append(s.logs, log) } - func (s *DBMsgStatus) Status() courier.MsgStatusValue { return s.Status_ } func (s *DBMsgStatus) SetStatus(status courier.MsgStatusValue) { s.Status_ = status } diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index 263262347..aecaed8c6 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -69,23 +69,23 @@ func (h *handler) Initialize(s courier.Server) error { return nil } -// { -// "statuses": [{ -// "id": "9712A34B4A8B6AD50F", -// "recipient_id": "16315555555", -// "status": "sent", -// "timestamp": "1518694700" -// }], -// "messages": [ { -// "from": "16315555555", -// "id": "3AF99CB6BE490DCAF641", -// "timestamp": "1518694235", -// "text": { -// "body": "Hello this is an answer" -// }, -// "type": "text" -// }] -// } +// { +// "statuses": [{ +// "id": "9712A34B4A8B6AD50F", +// "recipient_id": "16315555555", +// "status": "sent", +// "timestamp": "1518694700" +// }], +// "messages": [ { +// "from": "16315555555", +// "id": "3AF99CB6BE490DCAF641", +// "timestamp": "1518694235", +// "text": { +// "body": "Hello this is an answer" +// }, +// "type": "text" +// }] +// } type eventPayload struct { Contacts []struct { Profile struct { @@ -497,7 +497,6 @@ const maxMsgLength = 4096 // Send sends the given message, logging any HTTP calls or errors func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { - start := time.Now() conn := h.Backend().RedisPool().Get() defer conn.Close() @@ -517,25 +516,17 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) var wppID string - var logs []*courier.ChannelLog - payloads, logs, err := buildPayloads(msg, h) + payloads, err := buildPayloads(msg, h, logger) fail := payloads == nil && err != nil if fail { return nil, err } - for _, log := range logs { - status.AddLog(log) - } for i, payload := range payloads { externalID := "" - wppID, externalID, logs, err = sendWhatsAppMsg(conn, msg, sendPath, payload) - // add logs to our status - for _, log := range logs { - status.AddLog(log) - } + wppID, externalID, err = sendWhatsAppMsg(conn, msg, sendPath, payload, logger) if err != nil { break } @@ -554,9 +545,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha err = status.SetUpdatedURN(msg.URN(), newURN) if err != nil { - elapsed := time.Since(start) - log := courier.NewChannelLogFromError("unable to update contact URN", msg.Channel(), msg.ID(), elapsed, err) - status.AddLog(log) + logger.Error(err) } } status.SetStatus(courier.MsgWired) @@ -565,10 +554,8 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return status, nil } -func buildPayloads(msg courier.Msg, h *handler) ([]interface{}, []*courier.ChannelLog, error) { - start := time.Now() +func buildPayloads(msg courier.Msg, h *handler, logger *courier.ChannelLogger) ([]interface{}, error) { var payloads []interface{} - var logs []*courier.ChannelLog var err error parts := handlers.SplitMsgByChannel(msg.Channel(), msg.Text(), maxMsgLength) @@ -584,10 +571,7 @@ func buildPayloads(msg courier.Msg, h *handler) ([]interface{}, []*courier.Chann for attachmentCount, attachment := range msg.Attachments() { mimeType, mediaURL := handlers.SplitAttachment(attachment) - mediaID, mediaLogs, err := h.fetchMediaID(msg, mimeType, mediaURL) - if len(mediaLogs) > 0 { - logs = append(logs, mediaLogs...) - } + mediaID, err := h.fetchMediaID(msg, mimeType, mediaURL, logger) if err != nil { logrus.WithField("channel_uuid", msg.Channel().UUID().String()).WithError(err).Error("error while uploading media to whatsapp") } @@ -643,10 +627,7 @@ func buildPayloads(msg courier.Msg, h *handler) ([]interface{}, []*courier.Chann payload.Video = mediaPayload payloads = append(payloads, payload) } else { - duration := time.Since(start) - err = fmt.Errorf("unknown attachment mime type: %s", mimeType) - attachmentLogs := []*courier.ChannelLog{courier.NewChannelLogFromError("Error sending message", msg.Channel(), msg.ID(), duration, err)} - logs = append(logs, attachmentLogs...) + logger.Error(fmt.Errorf("unknown attachment mime type: %s", mimeType)) break } } @@ -730,7 +711,7 @@ func buildPayloads(msg courier.Msg, h *handler) ([]interface{}, []*courier.Chann var templating *MsgTemplating templating, err := h.getTemplate(msg) if err != nil { - return nil, nil, errors.Wrapf(err, "unable to decode template: %s for channel: %s", string(msg.Metadata()), msg.Channel().UUID()) + return nil, errors.Wrapf(err, "unable to decode template: %s for channel: %s", string(msg.Metadata()), msg.Channel().UUID()) } if templating != nil { namespace := templating.Namespace @@ -738,7 +719,7 @@ func buildPayloads(msg courier.Msg, h *handler) ([]interface{}, []*courier.Chann namespace = msg.Channel().StringConfigForKey(configNamespace, "") } if namespace == "" { - return nil, nil, errors.Errorf("cannot send template message without Facebook namespace for channel: %s", msg.Channel().UUID()) + return nil, errors.Errorf("cannot send template message without Facebook namespace for channel: %s", msg.Channel().UUID()) } if msg.Channel().BoolConfigForKey(configHSMSupport, false) { @@ -849,13 +830,11 @@ func buildPayloads(msg courier.Msg, h *handler) ([]interface{}, []*courier.Chann } } } - return payloads, logs, err + return payloads, err } // fetchMediaID tries to fetch the id for the uploaded media, setting the result in redis. -func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string) (string, []*courier.ChannelLog, error) { - var logs []*courier.ChannelLog - +func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string, logger *courier.ChannelLogger) (string, error) { // check in cache first rc := h.Backend().RedisPool().Get() defer rc.Close() @@ -864,9 +843,9 @@ func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string) (stri mediaCache := redisx.NewIntervalHash(cacheKey, time.Hour*24, 2) mediaID, err := mediaCache.Get(rc, mediaURL) if err != nil { - return "", logs, errors.Wrapf(err, "error reading media id from redis: %s : %s", cacheKey, mediaURL) + return "", errors.Wrapf(err, "error reading media id from redis: %s : %s", cacheKey, mediaURL) } else if mediaID != "" { - return mediaID, logs, nil + return mediaID, nil } // check in failure cache @@ -875,75 +854,69 @@ func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string) (stri // any non nil value means we cached a failure, don't try again until our cache expires if found != nil { - return "", logs, nil + return "", nil } // download media req, err := http.NewRequest("GET", mediaURL, nil) if err != nil { - return "", logs, errors.Wrapf(err, "error building media request") + return "", errors.Wrapf(err, "error building media request") } - trace, err := handlers.MakeHTTPRequest(req) - log := courier.NewChannelLogFromTrace("Fetching media", msg.Channel(), msg.ID(), trace).WithError("error fetching media", err) - logs = append(logs, log) - if err != nil { + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { failedMediaCache.Set(failKey, true, cache.DefaultExpiration) - return "", logs, nil + return "", nil } // upload media to WhatsApp baseURL := msg.Channel().StringConfigForKey(courier.ConfigBaseURL, "") url, err := url.Parse(baseURL) if err != nil { - return "", logs, errors.Wrapf(err, "invalid base url set for WA channel: %s", baseURL) + return "", errors.Wrapf(err, "invalid base url set for WA channel: %s", baseURL) } dockerMediaURL, _ := url.Parse("/v1/media") - req, err = http.NewRequest("POST", dockerMediaURL.String(), bytes.NewReader(trace.ResponseBody)) + req, err = http.NewRequest("POST", dockerMediaURL.String(), bytes.NewReader(respBody)) if err != nil { - return "", logs, errors.Wrapf(err, "error building request to media endpoint") + return "", errors.Wrapf(err, "error building request to media endpoint") } setWhatsAppAuthHeader(&req.Header, msg.Channel()) - req.Header.Add("Content-Type", httpx.DetectContentType(trace.ResponseBody)) + req.Header.Add("Content-Type", httpx.DetectContentType(respBody)) - trace, err = handlers.MakeHTTPRequest(req) - log = courier.NewChannelLogFromTrace("Uploading media to WhatsApp", msg.Channel(), msg.ID(), trace).WithError("Error uploading media to WhatsApp", err) - logs = append(logs, log) - if err != nil { + resp, respBody, err = handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { failedMediaCache.Set(failKey, true, cache.DefaultExpiration) - return "", logs, errors.Wrapf(err, "error uploading media to whatsapp") + return "", errors.Wrapf(err, "error uploading media to whatsapp") } // take uploaded media id - mediaID, err = jsonparser.GetString(trace.ResponseBody, "media", "[0]", "id") + mediaID, err = jsonparser.GetString(respBody, "media", "[0]", "id") if err != nil { - return "", logs, errors.Wrapf(err, "error reading media id from response") + return "", errors.Wrapf(err, "error reading media id from response") } // put in cache err = mediaCache.Set(rc, mediaURL, mediaID) if err != nil { - return "", logs, errors.Wrapf(err, "error setting media id in cache") + return "", errors.Wrapf(err, "error setting media id in cache") } - return mediaID, logs, nil + return mediaID, nil } -func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload interface{}) (string, string, []*courier.ChannelLog, error) { - start := time.Now() +func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload interface{}, logger *courier.ChannelLogger) (string, string, error) { jsonBody, err := json.Marshal(payload) if err != nil { - elapsed := time.Now().Sub(start) - log := courier.NewChannelLogFromError("unable to build JSON body", msg.Channel(), msg.ID(), elapsed, err) - return "", "", []*courier.ChannelLog{log}, err + return "", "", err } req, _ := http.NewRequest(http.MethodPost, sendPath.String(), bytes.NewReader(jsonBody)) req.Header = buildWhatsAppHeaders(msg.Channel()) - trace, err := handlers.MakeHTTPRequest(req) - if trace.Response != nil && (trace.Response.StatusCode == 429 || trace.Response.StatusCode == 503) { + resp, respBody, err := handlers.RequestHTTP(req, logger) + + if resp != nil && (resp.StatusCode == 429 || resp.StatusCode == 503) { rateLimitKey := fmt.Sprintf("rate_limit:%s", msg.Channel().UUID().String()) rc.Do("SET", rateLimitKey, "engaged") @@ -952,13 +925,11 @@ func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload // TODO: In the future we should the header value when available rc.Do("EXPIRE", rateLimitKey, 2) - log := courier.NewChannelLogFromTrace("rate limit engaged", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) - return "", "", []*courier.ChannelLog{log}, err + return "", "", err } - log := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), trace).WithError("Message Send Error", err) errPayload := &mtErrorPayload{} - err = json.Unmarshal(trace.ResponseBody, errPayload) + err = json.Unmarshal(respBody, errPayload) // handle send msg errors if err == nil && len(errPayload.Errors) > 0 { @@ -971,29 +942,24 @@ func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload rc.Do("EXPIRE", rateLimitBulkKey, (60*60*24)+(5*60)) err := errors.Errorf("received error from send endpoint: %s", errPayload.Errors[0].Title) - return "", "", []*courier.ChannelLog{log}, err + return "", "", err } if !hasWhatsAppContactError(*errPayload) { err := errors.Errorf("received error from send endpoint: %s", errPayload.Errors[0].Title) - return "", "", []*courier.ChannelLog{log}, err + return "", "", err } // check contact baseURL := fmt.Sprintf("%s://%s", sendPath.Scheme, sendPath.Host) - rrCheck, err := checkWhatsAppContact(msg.Channel(), baseURL, msg.URN()) - - if rrCheck == nil { - elapsed := time.Now().Sub(start) - checkLog := courier.NewChannelLogFromError("unable to build contact check request", msg.Channel(), msg.ID(), elapsed, err) - return "", "", []*courier.ChannelLog{log, checkLog}, err + checkResp, err := checkWhatsAppContact(msg.Channel(), baseURL, msg.URN(), logger) + if checkResp == nil { + return "", "", err } - checkLog := courier.NewChannelLogFromTrace("Contact check", msg.Channel(), msg.ID(), rrCheck).WithError("Status Error", err) - if err != nil { - return "", "", []*courier.ChannelLog{log, checkLog}, err + return "", "", err } // update contact URN and msg destiny with returned wpp id - wppID, err := jsonparser.GetString(rrCheck.ResponseBody, "contacts", "[0]", "wa_id") + wppID, err := jsonparser.GetString(checkResp, "contacts", "[0]", "wa_id") if err == nil { var updatedPayload interface{} @@ -1028,16 +994,14 @@ func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload jsonBody, err = json.Marshal(payload) if err != nil { - elapsed := time.Now().Sub(start) - log := courier.NewChannelLogFromError("unable to build JSON body", msg.Channel(), msg.ID(), elapsed, err) - return "", "", []*courier.ChannelLog{log, checkLog}, err + return "", "", err } } } // try send msg again reqRetry, err := http.NewRequest(http.MethodPost, sendPath.String(), bytes.NewReader(jsonBody)) if err != nil { - return "", "", nil, err + return "", "", err } reqRetry.Header = buildWhatsAppHeaders(msg.Channel()) @@ -1045,24 +1009,22 @@ func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload reqRetry.URL.RawQuery = fmt.Sprintf("%s=1", retryParam) } - traceRetry, err := handlers.MakeHTTPRequest(reqRetry) - retryLog := courier.NewChannelLogFromTrace("Message Sent", msg.Channel(), msg.ID(), traceRetry).WithError("Message Send Error", err) - - if err != nil { - return "", "", []*courier.ChannelLog{log, checkLog, retryLog}, err + retryResp, retryRespBody, err := handlers.RequestHTTP(reqRetry, logger) + if err != nil || retryResp.StatusCode/100 != 2 { + return "", "", errors.New("error making retry request") } - externalID, err := getSendWhatsAppMsgId(traceRetry.ResponseBody) - return wppID, externalID, []*courier.ChannelLog{log, checkLog, retryLog}, err + externalID, err := getSendWhatsAppMsgId(retryRespBody) + return wppID, externalID, err } - externalID, err := getSendWhatsAppMsgId(trace.ResponseBody) + externalID, err := getSendWhatsAppMsgId(respBody) if err != nil { - return "", "", []*courier.ChannelLog{log}, err + return "", "", err } - wppID, err := jsonparser.GetString(trace.ResponseBody, "contacts", "[0]", "wa_id") + wppID, err := jsonparser.GetString(respBody, "contacts", "[0]", "wa_id") if wppID != "" && wppID != msg.URN().Path() { - return wppID, externalID, []*courier.ChannelLog{log}, err + return wppID, externalID, err } - return "", externalID, []*courier.ChannelLog{log}, nil + return "", externalID, nil } func setWhatsAppAuthHeader(header *http.Header, channel courier.Channel) { @@ -1117,7 +1079,7 @@ type mtContactCheckPayload struct { ForceCheck bool `json:"force_check"` } -func checkWhatsAppContact(channel courier.Channel, baseURL string, urn urns.URN) (*httpx.Trace, error) { +func checkWhatsAppContact(channel courier.Channel, baseURL string, urn urns.URN, logger *courier.ChannelLogger) ([]byte, error) { payload := mtContactCheckPayload{ Blocking: "wait", Contacts: []string{fmt.Sprintf("+%s", urn.Path())}, @@ -1132,19 +1094,19 @@ func checkWhatsAppContact(channel courier.Channel, baseURL string, urn urns.URN) req, _ := http.NewRequest(http.MethodPost, sendURL, bytes.NewReader(reqBody)) req.Header = buildWhatsAppHeaders(channel) - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - return trace, err + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return nil, errors.New("error checking contact") } // check contact status - if status, err := jsonparser.GetString(trace.ResponseBody, "contacts", "[0]", "status"); err == nil { + if status, err := jsonparser.GetString(respBody, "contacts", "[0]", "status"); err == nil { if status == "valid" { - return trace, nil + return respBody, nil } else { - return trace, errors.Errorf(`contact status is "%s"`, status) + return respBody, errors.Errorf(`contact status is "%s"`, status) } } else { - return trace, err + return respBody, err } } diff --git a/sender.go b/sender.go index 6473a949b..181590597 100644 --- a/sender.go +++ b/sender.go @@ -201,11 +201,6 @@ func (w *Sender) sendMessage(msg Msg) { duration := time.Since(start) secondDuration := float64(duration) / float64(time.Second) - // handlers can currently return logs either via the logger or on the status object - if status != nil { - logger.logs = append(logger.logs, status.Logs()...) - } - if err != nil { log.WithError(err).WithField("elapsed", duration).Error("error sending message") logger.Error(err) diff --git a/status.go b/status.go index d02ac2c75..f957f6677 100644 --- a/status.go +++ b/status.go @@ -37,7 +37,4 @@ type MsgStatus interface { Status() MsgStatusValue SetStatus(MsgStatusValue) - - Logs() []*ChannelLog - AddLog(log *ChannelLog) } diff --git a/test/status.go b/test/status.go index f6ffe8a36..b601fda81 100644 --- a/test/status.go +++ b/test/status.go @@ -43,6 +43,3 @@ func (m *mockMsgStatus) SetExternalID(id string) { m.externalID = id } func (m *mockMsgStatus) Status() courier.MsgStatusValue { return m.status } func (m *mockMsgStatus) SetStatus(status courier.MsgStatusValue) { m.status = status } - -func (m *mockMsgStatus) Logs() []*courier.ChannelLog { return m.logs } -func (m *mockMsgStatus) AddLog(log *courier.ChannelLog) { m.logs = append(m.logs, log) } From 69625aa823df149d8f9fb2966613382f1ec95282 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 17 Aug 2022 14:59:17 -0500 Subject: [PATCH 080/294] Also remove code for storing logs on channel events --- backends/rapidpro/channel_event.go | 4 ---- channel_event.go | 3 --- handlers/whatsapp/whatsapp.go | 5 ++++- test/channel_event.go | 5 ----- 4 files changed, 4 insertions(+), 13 deletions(-) diff --git a/backends/rapidpro/channel_event.go b/backends/rapidpro/channel_event.go index d81879d8f..b99d7103f 100644 --- a/backends/rapidpro/channel_event.go +++ b/backends/rapidpro/channel_event.go @@ -197,7 +197,6 @@ type DBChannelEvent struct { ContactURNID_ ContactURNID `json:"-" db:"contact_urn_id"` channel *DBChannel - logs []*courier.ChannelLog } func (e *DBChannelEvent) EventID() int64 { return int64(e.ID_) } @@ -224,6 +223,3 @@ func (e *DBChannelEvent) WithOccurredOn(time time.Time) courier.ChannelEvent { e.OccurredOn_ = time return e } - -func (e *DBChannelEvent) Logs() []*courier.ChannelLog { return e.logs } -func (e *DBChannelEvent) AddLog(log *courier.ChannelLog) { e.logs = append(e.logs, log) } diff --git a/channel_event.go b/channel_event.go index b14cb372b..3fc7a7144 100644 --- a/channel_event.go +++ b/channel_event.go @@ -30,9 +30,6 @@ type ChannelEvent interface { CreatedOn() time.Time OccurredOn() time.Time - Logs() []*ChannelLog - AddLog(log *ChannelLog) - WithContactName(name string) ChannelEvent WithExtra(extra map[string]interface{}) ChannelEvent WithOccurredOn(time.Time) ChannelEvent diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index aecaed8c6..e43902aa0 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -915,6 +915,9 @@ func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload req.Header = buildWhatsAppHeaders(msg.Channel()) resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil { + return "", "", err + } if resp != nil && (resp.StatusCode == 429 || resp.StatusCode == 503) { rateLimitKey := fmt.Sprintf("rate_limit:%s", msg.Channel().UUID().String()) @@ -925,7 +928,7 @@ func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload // TODO: In the future we should the header value when available rc.Do("EXPIRE", rateLimitKey, 2) - return "", "", err + return "", "", errors.New("received rate-limit response from send endpoint") } errPayload := &mtErrorPayload{} diff --git a/test/channel_event.go b/test/channel_event.go index 77b43665d..4742d9ac6 100644 --- a/test/channel_event.go +++ b/test/channel_event.go @@ -16,8 +16,6 @@ type mockChannelEvent struct { contactName string extra map[string]interface{} - - logs []*courier.ChannelLog } func (e *mockChannelEvent) EventID() int64 { return 0 } @@ -41,6 +39,3 @@ func (e *mockChannelEvent) WithOccurredOn(time time.Time) courier.ChannelEvent { e.occurredOn = time return e } - -func (e *mockChannelEvent) Logs() []*courier.ChannelLog { return e.logs } -func (e *mockChannelEvent) AddLog(log *courier.ChannelLog) { e.logs = append(e.logs, log) } From ff4f10137a7ad9f35992f8914f83f1ffd1b7449c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 17 Aug 2022 16:49:24 -0500 Subject: [PATCH 081/294] Use httpx.Recorder to generate traces of incoming requests --- go.mod | 2 +- go.sum | 4 ++-- server.go | 61 ++++++++++++++++++++++++------------------------------- 3 files changed, 30 insertions(+), 37 deletions(-) diff --git a/go.mod b/go.mod index ec33152ae..4a25bdf99 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.6 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.26.0 + github.com/nyaruka/gocommon v1.27.0 github.com/nyaruka/null v1.2.0 github.com/nyaruka/redisx v0.2.2 github.com/patrickmn/go-cache v2.1.0+incompatible diff --git a/go.sum b/go.sum index 9ea11db60..108d67bc7 100644 --- a/go.sum +++ b/go.sum @@ -76,8 +76,8 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.26.0 h1:rpi2nhjXRTP7oMfG0P/pOJQH2nQBAHL/ygw/HYF6fxA= -github.com/nyaruka/gocommon v1.26.0/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= +github.com/nyaruka/gocommon v1.27.0 h1:cJoMmUgUdXNQDHBVEYHcNiFmTUgdciYUb+SmFM6m1ok= +github.com/nyaruka/gocommon v1.27.0/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= diff --git a/server.go b/server.go index 09a93f3e7..4eb61a6e6 100644 --- a/server.go +++ b/server.go @@ -8,7 +8,7 @@ import ( "fmt" "log" "net/http" - "net/http/httputil" + "net/url" "os" "runtime/debug" "sort" @@ -21,6 +21,7 @@ import ( "github.com/go-chi/chi/middleware" "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/analytics" + "github.com/nyaruka/gocommon/httpx" "github.com/sirupsen/logrus" ) @@ -271,9 +272,10 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe baseCtx := context.WithValue(r.Context(), contextRequestURL, r.URL.String()) baseCtx = context.WithValue(baseCtx, contextRequestStart, time.Now()) - // add a 30 second timeout + // add a 30 second timeout to the request ctx, cancel := context.WithTimeout(baseCtx, time.Second*30) defer cancel() + r = r.WithContext(ctx) channel, err := handler.GetChannel(ctx, r) if err != nil { @@ -281,22 +283,18 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe return } - r = r.WithContext(ctx) - - // read the bytes from our body so we can create a channel log for this request - response := &bytes.Buffer{} - - // Trim out cookie header, should never be part of authentication and can leak auth to channel logs + // trim out cookie header, should never be part of authentication and can leak auth to channel logs r.Header.Del("Cookie") - request, err := httputil.DumpRequest(r, true) + + recorder, err := httpx.NewRecorder(r, w) if err != nil { writeAndLogRequestError(ctx, w, r, channel, err) return } - url := fmt.Sprintf("https://%s%s", r.Host, r.URL.RequestURI()) - ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor) - ww.Tee(response) + // change the URL of the request to be our www facing hostname + requestURL, _ := url.Parse(fmt.Sprintf("https://%s%s", r.Host, r.URL.RequestURI())) + recorder.Trace.Request.URL = requestURL logs := make([]*ChannelLog, 0, 1) @@ -305,28 +303,34 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe panicLog := recover() if panicLog != nil { debug.PrintStack() - logrus.WithError(err).WithField("channel_uuid", channel.UUID()).WithField("url", url).WithField("request", string(request)).WithField("trace", panicLog).Error("panic handling request") - writeAndLogRequestError(ctx, ww, r, channel, errors.New("panic handling msg")) + logrus.WithError(err).WithField("channel_uuid", channel.UUID()).WithField("request", string(recorder.Trace.RequestTrace)).WithField("trace", panicLog).Error("panic handling request") + writeAndLogRequestError(ctx, recorder.ResponseWriter, r, channel, errors.New("panic handling msg")) } }() - events, err := handlerFunc(ctx, channel, ww, r) + events, err := handlerFunc(ctx, channel, recorder.ResponseWriter, r) duration := time.Since(start) secondDuration := float64(duration) / float64(time.Second) // if we received an error, write it out and report it if err != nil { - logrus.WithError(err).WithField("channel_uuid", channel.UUID()).WithField("url", url).WithField("request", string(request)).Error("error handling request") - writeAndLogRequestError(ctx, ww, r, channel, err) + logrus.WithError(err).WithField("channel_uuid", channel.UUID()).WithField("request", string(recorder.Trace.RequestTrace)).Error("error handling request") + writeAndLogRequestError(ctx, recorder.ResponseWriter, r, channel, err) + } + + // end recording of the request so that we have a response trace + if err := recorder.End(); err != nil { + logrus.WithError(err).WithField("channel_uuid", channel.UUID()).WithField("request", string(recorder.Trace.RequestTrace)).Error("error receording request") + writeAndLogRequestError(ctx, w, r, channel, err) } // if we have a channel matched but no events were created we still want to log this to the channel, do so if channel != nil && len(events) == 0 { if err != nil { - logs = append(logs, NewChannelLog("Channel Error", channel, NilMsgID, r.Method, url, ww.Status(), string(request), prependHeaders(response.String(), ww.Status(), w), duration, err)) + logs = append(logs, NewChannelLogFromTrace("Channel Error", channel, NilMsgID, recorder.Trace).WithError("Channel Error", err)) analytics.Gauge(fmt.Sprintf("courier.channel_error_%s", channel.ChannelType()), secondDuration) } else { - logs = append(logs, NewChannelLog("Request Ignored", channel, NilMsgID, r.Method, url, ww.Status(), string(request), prependHeaders(response.String(), ww.Status(), w), duration, err)) + logs = append(logs, NewChannelLogFromTrace("Request Ignored", channel, NilMsgID, recorder.Trace)) analytics.Gauge(fmt.Sprintf("courier.channel_ignored_%s", channel.ChannelType()), secondDuration) } } @@ -335,24 +339,22 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe for _, event := range events { switch e := event.(type) { case Msg: - logs = append(logs, NewChannelLog("Message Received", channel, e.ID(), r.Method, url, ww.Status(), string(request), prependHeaders(response.String(), ww.Status(), w), duration, err)) + logs = append(logs, NewChannelLogFromTrace("Message Receive", channel, e.ID(), recorder.Trace).WithError("Message Receive", err)) analytics.Gauge(fmt.Sprintf("courier.msg_receive_%s", channel.ChannelType()), secondDuration) LogMsgReceived(r, e) case ChannelEvent: - logs = append(logs, NewChannelLog("Event Received", channel, NilMsgID, r.Method, url, ww.Status(), string(request), prependHeaders(response.String(), ww.Status(), w), duration, err)) + logs = append(logs, NewChannelLogFromTrace("Event Receive", channel, NilMsgID, recorder.Trace).WithError("Event Receive", err)) analytics.Gauge(fmt.Sprintf("courier.evt_receive_%s", channel.ChannelType()), secondDuration) LogChannelEventReceived(r, e) case MsgStatus: - logs = append(logs, NewChannelLog("Status Updated", channel, e.ID(), r.Method, url, ww.Status(), string(request), response.String(), duration, err)) + logs = append(logs, NewChannelLogFromTrace("Status Update", channel, e.ID(), recorder.Trace).WithError("Status Update", err)) analytics.Gauge(fmt.Sprintf("courier.msg_status_%s", channel.ChannelType()), secondDuration) LogMsgStatusReceived(r, e) } } - // and write these out + // and write these out, logging if there's an error err = s.backend.WriteChannelLogs(ctx, logs) - - // log any error writing our channel log but don't break the request if err != nil { logrus.WithError(err).Error("error writing channel log") } @@ -375,15 +377,6 @@ func (s *server) AddHandlerRoute(handler ChannelHandler, method string, action s s.routes = append(s.routes, fmt.Sprintf("%-20s - %s %s", "/c"+path, handler.ChannelName(), action)) } -func prependHeaders(body string, statusCode int, resp http.ResponseWriter) string { - output := &bytes.Buffer{} - output.WriteString(fmt.Sprintf("HTTP/1.1 %d %s\r\n", statusCode, http.StatusText(statusCode))) - resp.Header().Write(output) - output.WriteString("\n") - output.WriteString(body) - return output.String() -} - func (s *server) handleIndex(w http.ResponseWriter, r *http.Request) { var buf bytes.Buffer From f9ad1fe4ea6c1482839f3c2cf884a061d19a58b0 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 17 Aug 2022 16:54:29 -0500 Subject: [PATCH 082/294] Remove no longer used NewChannelLog function --- backends/rapidpro/backend_test.go | 18 +++++++++++++++--- channel_log.go | 24 ------------------------ 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index d16c97142..a6fae187b 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -18,6 +18,7 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/queue" "github.com/nyaruka/gocommon/dbutil/assertdb" + "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/storage" "github.com/nyaruka/gocommon/urns" "github.com/nyaruka/null" @@ -948,10 +949,21 @@ func (ts *BackendTestSuite) TestChanneLog() { knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") ctx := context.Background() - log := courier.NewChannelLog("Message Send Error", knChannel, courier.NilMsgID, "POST", "/null/value", 400, - "request with null \x00 content", "response with null \x00 content", time.Millisecond, nil) + httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ + "https://api.messages.com/send.json": { + httpx.NewMockResponse(200, nil, []byte(`{"status":"success"}`)), + }, + })) + defer httpx.SetRequestor(httpx.DefaultRequestor) + + // make a request that will have a response + req, _ := http.NewRequest("POST", "https://api.messages.com/send.json", nil) + trace, err := httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) + ts.NoError(err) + + log := courier.NewChannelLogFromTrace("Message Send Error", knChannel, courier.NilMsgID, trace) - err := writeChannelLog(ctx, ts.b, log) + err = writeChannelLog(ctx, ts.b, log) ts.NoError(err) } diff --git a/channel_log.go b/channel_log.go index f159cf825..32cd59959 100644 --- a/channel_log.go +++ b/channel_log.go @@ -8,30 +8,6 @@ import ( "github.com/nyaruka/gocommon/httpx" ) -// NewChannelLog creates a new channel log for the passed in channel, id, and request and response info -func NewChannelLog(description string, channel Channel, msgID MsgID, method string, url string, statusCode int, - request string, response string, elapsed time.Duration, err error) *ChannelLog { - - errString := "" - if err != nil { - errString = err.Error() - } - - return &ChannelLog{ - Description: description, - Channel: channel, - MsgID: msgID, - Method: method, - URL: url, - StatusCode: statusCode, - Error: errString, - Request: SanitizeBody(request), - Response: SanitizeBody(response), - CreatedOn: time.Now(), - Elapsed: elapsed, - } -} - func SanitizeBody(body string) string { parts := strings.SplitN(body, "\r\n\r\n", 2) if len(parts) < 2 { From a162b821b8b2ae67414c9d7901550ae82de89962 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 18 Aug 2022 08:39:03 -0500 Subject: [PATCH 083/294] Update CHANGELOG.md for v7.5.13 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index baf62ce64..87cd973a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.13 +---------- + * Use httpx.Recorder to generate traces of incoming requests + * Rework WhatsApp handler to use logger, remove code for storing logs on status objects + v7.5.12 ---------- * Adjust LINE to support sending attachments with quick replies later From bb18c4f8de6b877d240d5b90e8da2a241cc62ed6 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Sat, 20 Aug 2022 14:22:53 -0500 Subject: [PATCH 084/294] Update to latest gocommon and use new recorder reconstruct option --- go.mod | 2 +- go.sum | 4 ++-- handler_test.go | 4 ---- server.go | 13 ++----------- 4 files changed, 5 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 4a25bdf99..be68d8438 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.6 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.27.0 + github.com/nyaruka/gocommon v1.28.1 github.com/nyaruka/null v1.2.0 github.com/nyaruka/redisx v0.2.2 github.com/patrickmn/go-cache v2.1.0+incompatible diff --git a/go.sum b/go.sum index 108d67bc7..ae7896c5a 100644 --- a/go.sum +++ b/go.sum @@ -76,8 +76,8 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.27.0 h1:cJoMmUgUdXNQDHBVEYHcNiFmTUgdciYUb+SmFM6m1ok= -github.com/nyaruka/gocommon v1.27.0/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= +github.com/nyaruka/gocommon v1.28.1 h1:/BI8G0pv6M3+rphJhVF8CfU2/bTOzE+LF+HRGETNfhI= +github.com/nyaruka/gocommon v1.28.1/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= diff --git a/handler_test.go b/handler_test.go index b28aa62d8..f0443d1e8 100644 --- a/handler_test.go +++ b/handler_test.go @@ -144,8 +144,4 @@ func TestHandling(t *testing.T) { defer resp.Body.Close() body, _ = io.ReadAll(resp.Body) assert.Contains(string(body), "ok") - - // cookie stripped - log, _ := mb.GetLastChannelLog() - assert.NotContains(log.Request, "secret") } diff --git a/server.go b/server.go index 4eb61a6e6..b98c9c5a3 100644 --- a/server.go +++ b/server.go @@ -8,14 +8,12 @@ import ( "fmt" "log" "net/http" - "net/url" "os" "runtime/debug" "sort" "strings" - "time" - "sync" + "time" "github.com/go-chi/chi" "github.com/go-chi/chi/middleware" @@ -283,19 +281,12 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe return } - // trim out cookie header, should never be part of authentication and can leak auth to channel logs - r.Header.Del("Cookie") - - recorder, err := httpx.NewRecorder(r, w) + recorder, err := httpx.NewRecorder(r, w, true) if err != nil { writeAndLogRequestError(ctx, w, r, channel, err) return } - // change the URL of the request to be our www facing hostname - requestURL, _ := url.Parse(fmt.Sprintf("https://%s%s", r.Host, r.URL.RequestURI())) - recorder.Trace.Request.URL = requestURL - logs := make([]*ChannelLog, 0, 1) defer func() { From f8185e9e47a5f86bd3f66f1bbc6b4185ac5ba9fa Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 22 Aug 2022 15:51:42 -0500 Subject: [PATCH 085/294] Update to latest gocommon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index be68d8438..1ac43f7e2 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.6 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.28.1 + github.com/nyaruka/gocommon v1.28.2 github.com/nyaruka/null v1.2.0 github.com/nyaruka/redisx v0.2.2 github.com/patrickmn/go-cache v2.1.0+incompatible diff --git a/go.sum b/go.sum index ae7896c5a..b192d805d 100644 --- a/go.sum +++ b/go.sum @@ -76,8 +76,8 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.28.1 h1:/BI8G0pv6M3+rphJhVF8CfU2/bTOzE+LF+HRGETNfhI= -github.com/nyaruka/gocommon v1.28.1/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= +github.com/nyaruka/gocommon v1.28.2 h1:1RoQWH2lJUszOL/fDgA72ktQ6z6vcz0PHKJJL73+s40= +github.com/nyaruka/gocommon v1.28.2/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= From ae12c626c65ea5cfcdeb1565f3eabcb0cb1f3fff Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 23 Aug 2022 08:27:30 -0500 Subject: [PATCH 086/294] Update CHANGELOG.md for v7.5.14 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87cd973a0..d154aec97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.14 +---------- + * Update to latest gocommon and use new recorder reconstruct option + v7.5.13 ---------- * Use httpx.Recorder to generate traces of incoming requests From 2a0c118d54b9f2334be7210d1e11b532377c36f9 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 23 Aug 2022 10:42:04 -0500 Subject: [PATCH 087/294] Update handler funcs to take logger instance --- channel_log.go | 6 +- handler.go | 2 +- handler_test.go | 2 +- handlers/africastalking/africastalking.go | 4 +- handlers/blackmyna/blackmyna.go | 4 +- handlers/bongolive/bongolive.go | 2 +- handlers/chikka/chikka.go | 2 +- handlers/clickatell/clickatell.go | 4 +- handlers/clickmobile/clickmobile.go | 2 +- handlers/dart/dart.go | 4 +- handlers/discord/discord.go | 8 +-- handlers/dmark/dmark.go | 4 +- handlers/external/external.go | 10 +-- handlers/facebook/facebook.go | 4 +- handlers/facebookapp/facebookapp.go | 4 +- handlers/firebase/firebase.go | 4 +- handlers/freshchat/freshchat.go | 2 +- handlers/generic.go | 4 +- handlers/globe/globe.go | 50 +++++++------- handlers/highconnection/highconnection.go | 4 +- handlers/hormuud/hormuud.go | 2 +- handlers/i2sms/i2sms.go | 22 +++--- handlers/infobip/infobip.go | 46 ++++++------- handlers/jasmin/jasmin.go | 4 +- handlers/jiochat/jiochat.go | 4 +- handlers/junebug/junebug.go | 44 ++++++------ handlers/kaleyra/kaleyra.go | 4 +- handlers/kannel/kannel.go | 4 +- handlers/line/line.go | 56 ++++++++-------- handlers/m3tech/m3tech.go | 2 +- handlers/macrokiosk/macrokiosk.go | 4 +- handlers/mblox/mblox.go | 2 +- handlers/mtarget/mtarget.go | 2 +- handlers/nexmo/nexmo.go | 4 +- handlers/novo/novo.go | 2 +- handlers/playmobile/playmobile.go | 2 +- handlers/plivo/plivo.go | 4 +- handlers/rocketchat/rocketchat.go | 2 +- handlers/shaqodoon/shaqodoon.go | 2 +- handlers/slack/slack.go | 2 +- handlers/smscentral/smscentral.go | 2 +- handlers/start/start.go | 2 +- handlers/telegram/telegram.go | 2 +- handlers/telesom/telesom.go | 2 +- handlers/thinq/thinq.go | 4 +- handlers/twiml/twiml.go | 4 +- handlers/twitter/twitter.go | 82 +++++++++++------------ handlers/viber/viber.go | 2 +- handlers/vk/vk.go | 2 +- handlers/wavy/wavy.go | 6 +- handlers/wechat/wechat.go | 4 +- handlers/whatsapp/whatsapp.go | 2 +- handlers/yo/yo.go | 2 +- handlers/zenvia/zenvia.go | 6 +- handlers/zenviaold/zenviaold.go | 68 +++++++++---------- server.go | 4 +- 56 files changed, 267 insertions(+), 267 deletions(-) diff --git a/channel_log.go b/channel_log.go index 32cd59959..f81fc5082 100644 --- a/channel_log.go +++ b/channel_log.go @@ -97,8 +97,8 @@ const ( ) var logTypeDescriptions = map[ChannelLogType]string{ - ChannelLogTypeMessageSend: "Message Sent", - ChannelLogTypeMessageReceive: "Message Received", + ChannelLogTypeMessageSend: "Message Send", + ChannelLogTypeMessageReceive: "Message Receive", } var logTypeErrorDescriptions = map[ChannelLogType]string{ ChannelLogTypeMessageSend: "Message Sending Error", @@ -119,7 +119,7 @@ func NewChannelLoggerForSend(msg Msg) *ChannelLogger { } func NewChannelLoggerForReceive(channel Channel) *ChannelLogger { - return &ChannelLogger{type_: ChannelLogTypeMessageSend, channel: channel} + return &ChannelLogger{type_: ChannelLogTypeMessageReceive, channel: channel} } // HTTP logs an HTTP request and response diff --git a/handler.go b/handler.go index fb0277f5b..1aab538b5 100644 --- a/handler.go +++ b/handler.go @@ -16,7 +16,7 @@ type Event interface { // The Server will take care of looking up the channel by UUID before passing it to this function. // Errors in format of the request or by the caller should be handled and logged internally. Errors in // execution or in courier itself should be passed back. -type ChannelHandleFunc func(context.Context, Channel, http.ResponseWriter, *http.Request) ([]Event, error) +type ChannelHandleFunc func(context.Context, Channel, http.ResponseWriter, *http.Request, *ChannelLogger) ([]Event, error) // ChannelHandler is the interface all handlers must satisfy type ChannelHandler interface { diff --git a/handler_test.go b/handler_test.go index f0443d1e8..5fb833c7a 100644 --- a/handler_test.go +++ b/handler_test.go @@ -51,7 +51,7 @@ func (h *dummyHandler) Send(ctx context.Context, msg courier.Msg, logger *courie } // ReceiveMsg sends the passed in message, returning any error -func (h *dummyHandler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *dummyHandler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { r.ParseForm() from := r.Form.Get("from") text := r.Form.Get("text") diff --git a/handlers/africastalking/africastalking.go b/handlers/africastalking/africastalking.go index cec24a32e..7db6ce1ae 100644 --- a/handlers/africastalking/africastalking.go +++ b/handlers/africastalking/africastalking.go @@ -48,7 +48,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -94,7 +94,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) diff --git a/handlers/blackmyna/blackmyna.go b/handlers/blackmyna/blackmyna.go index 3f3a220c1..c95bf97c9 100644 --- a/handlers/blackmyna/blackmyna.go +++ b/handlers/blackmyna/blackmyna.go @@ -42,7 +42,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -76,7 +76,7 @@ var statusMapping = map[int]courier.MsgStatusValue{ } // StatusMessage is our HTTP handler function for status updates -func (h *handler) StatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) StatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) diff --git a/handlers/bongolive/bongolive.go b/handlers/bongolive/bongolive.go index 1bcf5630b..4e85819cb 100644 --- a/handlers/bongolive/bongolive.go +++ b/handlers/bongolive/bongolive.go @@ -64,7 +64,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { var err error form := &moForm{} err = handlers.DecodeAndValidateForm(form, r) diff --git a/handlers/chikka/chikka.go b/handlers/chikka/chikka.go index a76749a4e..261fac305 100644 --- a/handlers/chikka/chikka.go +++ b/handlers/chikka/chikka.go @@ -56,7 +56,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) diff --git a/handlers/clickatell/clickatell.go b/handlers/clickatell/clickatell.go index 5a49cbc79..2de80cc3f 100644 --- a/handlers/clickatell/clickatell.go +++ b/handlers/clickatell/clickatell.go @@ -65,7 +65,7 @@ var statusMapping = map[int]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &statusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) @@ -99,7 +99,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) diff --git a/handlers/clickmobile/clickmobile.go b/handlers/clickmobile/clickmobile.go index 367d15557..cca1a1421 100644 --- a/handlers/clickmobile/clickmobile.go +++ b/handlers/clickmobile/clickmobile.go @@ -59,7 +59,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateXML(payload, r) if err != nil { diff --git a/handlers/dart/dart.go b/handlers/dart/dart.go index 69ba48e29..5efca19b8 100644 --- a/handlers/dart/dart.go +++ b/handlers/dart/dart.go @@ -56,7 +56,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -89,7 +89,7 @@ type statusForm struct { } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { diff --git a/handlers/discord/discord.go b/handlers/discord/discord.go index 7f6d3f4c6..353895a60 100644 --- a/handlers/discord/discord.go +++ b/handlers/discord/discord.go @@ -69,7 +69,7 @@ func getFormField(form url.Values, name string) string { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { var err error var from, text string @@ -119,8 +119,8 @@ func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWr // buildStatusHandler deals with building a handler that takes what status is received in the URL func (h *handler) buildStatusHandler(status string) courier.ChannelHandleFunc { - return func(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { - return h.receiveStatus(ctx, status, channel, w, r) + return func(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { + return h.receiveStatus(ctx, status, channel, w, r, logger) } } @@ -135,7 +135,7 @@ var statusMappings = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, statusString string, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, statusString string, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { diff --git a/handlers/dmark/dmark.go b/handlers/dmark/dmark.go index cfb8ea6a6..620082d2e 100644 --- a/handlers/dmark/dmark.go +++ b/handlers/dmark/dmark.go @@ -47,7 +47,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -88,7 +88,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) diff --git a/handlers/external/external.go b/handlers/external/external.go index 326344ec4..a012d2a42 100644 --- a/handlers/external/external.go +++ b/handlers/external/external.go @@ -93,7 +93,7 @@ type stopContactForm struct { From string `validate:"required" name:"from"` } -func (h *handler) receiveStopContact(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStopContact(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &stopContactForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -142,7 +142,7 @@ func getFormField(form url.Values, defaultNames []string, name string) string { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { var err error var from, dateString, text string @@ -238,8 +238,8 @@ func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWr // buildStatusHandler deals with building a handler that takes what status is received in the URL func (h *handler) buildStatusHandler(status string) courier.ChannelHandleFunc { - return func(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { - return h.receiveStatus(ctx, status, channel, w, r) + return func(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { + return h.receiveStatus(ctx, status, channel, w, r, logger) } } @@ -254,7 +254,7 @@ var statusMappings = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, statusString string, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, statusString string, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { diff --git a/handlers/facebook/facebook.go b/handlers/facebook/facebook.go index 621038053..4771c5e22 100644 --- a/handlers/facebook/facebook.go +++ b/handlers/facebook/facebook.go @@ -77,7 +77,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveVerify handles Facebook's webhook verification callback -func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { mode := r.URL.Query().Get("hub.mode") // this isn't a subscribe verification, that's an error @@ -206,7 +206,7 @@ type moPayload struct { } // receiveEvent is our HTTP handler function for incoming messages and status updates -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 0b8c85134..0b587628f 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -312,7 +312,7 @@ func (h *handler) GetChannel(ctx context.Context, r *http.Request) (courier.Chan } // receiveVerify handles Facebook's webhook verification callback -func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { mode := r.URL.Query().Get("hub.mode") // this isn't a subscribe verification, that's an error @@ -354,7 +354,7 @@ func resolveMediaURL(mediaID string, token string) (string, error) { } // receiveEvent is our HTTP handler function for incoming messages and status updates -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { err := h.validateSignature(r) if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) diff --git a/handlers/firebase/firebase.go b/handlers/firebase/firebase.go index a86454b8d..7226676b4 100644 --- a/handlers/firebase/firebase.go +++ b/handlers/firebase/firebase.go @@ -54,7 +54,7 @@ type receiveForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &receiveForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -89,7 +89,7 @@ type registerForm struct { } // registerContact is our HTTP handler function for when a contact is registered (or renewed) -func (h *handler) registerContact(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) registerContact(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := ®isterForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { diff --git a/handlers/freshchat/freshchat.go b/handlers/freshchat/freshchat.go index 8ffade2a4..fee86ec00 100644 --- a/handlers/freshchat/freshchat.go +++ b/handlers/freshchat/freshchat.go @@ -48,7 +48,7 @@ func (h *handler) Initialize(s courier.Server) error { s.AddHandlerRoute(h, http.MethodPost, "receive", h.receiveMessage) return nil } -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { err := h.validateSignature(channel, r) if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) diff --git a/handlers/generic.go b/handlers/generic.go index 65509d5c1..0e7180da9 100644 --- a/handlers/generic.go +++ b/handlers/generic.go @@ -11,7 +11,7 @@ import ( // NewTelReceiveHandler creates a new receive handler given the passed in text and from fields func NewTelReceiveHandler(h *BaseHandler, fromField string, bodyField string) courier.ChannelHandleFunc { - return func(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { + return func(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, WriteAndLogRequestError(ctx, h, c, w, r, err) @@ -35,7 +35,7 @@ func NewTelReceiveHandler(h *BaseHandler, fromField string, bodyField string) co // NewExternalIDStatusHandler creates a new status handler given the passed in status map and fields func NewExternalIDStatusHandler(h *BaseHandler, statuses map[string]courier.MsgStatusValue, externalIDField string, statusField string) courier.ChannelHandleFunc { - return func(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { + return func(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, WriteAndLogRequestError(ctx, h, c, w, r, err) diff --git a/handlers/globe/globe.go b/handlers/globe/globe.go index 823cfec97..458da045c 100644 --- a/handlers/globe/globe.go +++ b/handlers/globe/globe.go @@ -43,23 +43,23 @@ func (h *handler) Initialize(s courier.Server) error { return nil } -// { -// "inboundSMSMessageList":{ -// "inboundSMSMessage":[ -// { -// "dateTime":"Fri Nov 22 2013 12:12:13 GMT+0000 (UTC)", -// "destinationAddress":"tel:21581234", -// "messageId":null, -// "message":"Hello", -// "resourceURL":null, -// "senderAddress":"tel:+639171234567" -// } -// ], -// "numberOfMessagesInThisBatch":1, -// "resourceURL":null, -// "totalNumberOfPendingMessages":null -// } -// } +// { +// "inboundSMSMessageList":{ +// "inboundSMSMessage":[ +// { +// "dateTime":"Fri Nov 22 2013 12:12:13 GMT+0000 (UTC)", +// "destinationAddress":"tel:21581234", +// "messageId":null, +// "message":"Hello", +// "resourceURL":null, +// "senderAddress":"tel:+639171234567" +// } +// ], +// "numberOfMessagesInThisBatch":1, +// "resourceURL":null, +// "totalNumberOfPendingMessages":null +// } +// } type moPayload struct { InboundSMSMessageList struct { InboundSMSMessage []struct { @@ -73,7 +73,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -110,13 +110,13 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. return handlers.WriteMsgsAndResponse(ctx, h, msgs, w, r) } -// { -// "address": "250788383383", -// "message": "hello world", -// "passphrase": "my passphrase", -// "app_id": "my app id", -// "app_secret": "my app secret" -// } +// { +// "address": "250788383383", +// "message": "hello world", +// "passphrase": "my passphrase", +// "app_id": "my app id", +// "app_secret": "my app secret" +// } type mtPayload struct { Address string `json:"address"` Message string `json:"message"` diff --git a/handlers/highconnection/highconnection.go b/handlers/highconnection/highconnection.go index 63aae3dc1..4191eb28b 100644 --- a/handlers/highconnection/highconnection.go +++ b/handlers/highconnection/highconnection.go @@ -46,7 +46,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -98,7 +98,7 @@ var statusMapping = map[int]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { diff --git a/handlers/hormuud/hormuud.go b/handlers/hormuud/hormuud.go index 7bbc2d47d..b8cb0b432 100644 --- a/handlers/hormuud/hormuud.go +++ b/handlers/hormuud/hormuud.go @@ -51,7 +51,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateForm(payload, r) if err != nil { diff --git a/handlers/i2sms/i2sms.go b/handlers/i2sms/i2sms.go index 3aa454ff3..bf14fdc71 100644 --- a/handlers/i2sms/i2sms.go +++ b/handlers/i2sms/i2sms.go @@ -42,7 +42,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receive is our handler for MO messages -func (h *handler) receive(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receive(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, err) @@ -65,16 +65,16 @@ func (h *handler) receive(ctx context.Context, c courier.Channel, w http.Respons return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) } -// { -// "​result​":{ -// "submit_result":"OK", -// "session_id":"5b8fc97d58795484819426", -// "status_code":"00", -// "status_message":"Submitted ok" -// }, -// "​error_code​":"00", -// "error_desc​":"Completed OK" -// } +// { +// "​result​":{ +// "submit_result":"OK", +// "session_id":"5b8fc97d58795484819426", +// "status_code":"00", +// "status_message":"Submitted ok" +// }, +// "​error_code​":"00", +// "error_desc​":"Completed OK" +// } type mtResponse struct { Result struct { SessionID string `json:"session_id"` diff --git a/handlers/infobip/infobip.go b/handlers/infobip/infobip.go index 118f3d6cc..a805ee443 100644 --- a/handlers/infobip/infobip.go +++ b/handlers/infobip/infobip.go @@ -58,7 +58,7 @@ type ibStatus struct { } // statusMessage is our HTTP handler function for status updates -func (h *handler) statusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) statusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &statusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -91,27 +91,27 @@ func (h *handler) statusMessage(ctx context.Context, channel courier.Channel, w return statuses, courier.WriteDataResponse(ctx, w, http.StatusOK, "statuses handled", data) } -// { -// "results": [ -// { -// "messageId": "817790313235066447", -// "from": "385916242493", -// "to": "385921004026", -// "text": "QUIZ Correct answer is Paris", -// "cleanText": "Correct answer is Paris", -// "keyword": "QUIZ", -// "receivedAt": "2016-10-06T09:28:39.220+0000", -// "smsCount": 1, -// "price": { -// "pricePerMessage": 0, -// "currency": "EUR" -// }, -// "callbackData": "callbackData" -// } -// ], -// "messageCount": 1, -// "pendingMessageCount": 0 -// } +// { +// "results": [ +// { +// "messageId": "817790313235066447", +// "from": "385916242493", +// "to": "385921004026", +// "text": "QUIZ Correct answer is Paris", +// "cleanText": "Correct answer is Paris", +// "keyword": "QUIZ", +// "receivedAt": "2016-10-06T09:28:39.220+0000", +// "smsCount": 1, +// "price": { +// "pricePerMessage": 0, +// "currency": "EUR" +// }, +// "callbackData": "callbackData" +// } +// ], +// "messageCount": 1, +// "pendingMessageCount": 0 +// } type moPayload struct { PendingMessageCount int `json:"pendingMessageCount"` MessageCount int `json:"messageCount"` @@ -126,7 +126,7 @@ type moMessage struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { diff --git a/handlers/jasmin/jasmin.go b/handlers/jasmin/jasmin.go index 299a7de53..3d67a5e16 100644 --- a/handlers/jasmin/jasmin.go +++ b/handlers/jasmin/jasmin.go @@ -43,7 +43,7 @@ type statusForm struct { } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -73,7 +73,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index bb98463b4..7b0c57158 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -63,7 +63,7 @@ type verifyForm struct { } // VerifyURL is our HTTP handler function for Jiochat config URL verification callbacks -func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &verifyForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -108,7 +108,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { diff --git a/handlers/junebug/junebug.go b/handlers/junebug/junebug.go index 0afb6b168..a9a8fe3ab 100644 --- a/handlers/junebug/junebug.go +++ b/handlers/junebug/junebug.go @@ -38,14 +38,14 @@ func (h *handler) Initialize(s courier.Server) error { return nil } -// { -// "from": "+27123456789", -// "timestamp": "2017-01-01 00:00:00.00", -// "content": "content", -// "to": "to-addr", -// "reply_to": null, -// "message_id": "message-id" -// } +// { +// "from": "+27123456789", +// "timestamp": "2017-01-01 00:00:00.00", +// "content": "content", +// "to": "to-addr", +// "reply_to": null, +// "message_id": "message-id" +// } type moPayload struct { From string `json:"from" validate:"required"` Timestamp string `json:"timestamp" validate:"required"` @@ -56,7 +56,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -89,11 +89,11 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) } -// { -// 'event_type': 'submitted', -// 'message_id': 'message-id', -// 'timestamp': '2017-01-01 00:00:00+0000', -// } +// { +// 'event_type': 'submitted', +// 'message_id': 'message-id', +// 'timestamp': '2017-01-01 00:00:00+0000', +// } type eventPayload struct { EventType string `json:"event_type" validate:"required"` MessageID string `json:"message_id" validate:"required"` @@ -108,7 +108,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveEvent is our HTTP handler function for incoming events -func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &eventPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -139,13 +139,13 @@ func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.Re return handlers.WriteMsgStatusAndResponse(ctx, h, c, status, w, r) } -// { -// "event_url": "https://callback.com/event", -// "content": "hello world", -// "from": "2020", -// "to": "+250788383383", -// "event_auth_token": "secret", -// } +// { +// "event_url": "https://callback.com/event", +// "content": "hello world", +// "from": "2020", +// "to": "+250788383383", +// "event_auth_token": "secret", +// } type mtPayload struct { EventURL string `json:"event_url"` Content string `json:"content"` diff --git a/handlers/kaleyra/kaleyra.go b/handlers/kaleyra/kaleyra.go index 3111c3230..8af1548dc 100644 --- a/handlers/kaleyra/kaleyra.go +++ b/handlers/kaleyra/kaleyra.go @@ -65,7 +65,7 @@ type moStatusForm struct { } // receiveMsg is our HTTP handler function for incoming messages -func (h *handler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &moMsgForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -113,7 +113,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for outgoing messages statuses -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &moStatusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { diff --git a/handlers/kannel/kannel.go b/handlers/kannel/kannel.go index 60e6a36f5..004c16e39 100644 --- a/handlers/kannel/kannel.go +++ b/handlers/kannel/kannel.go @@ -56,7 +56,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -94,7 +94,7 @@ type statusForm struct { } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) diff --git a/handlers/line/line.go b/handlers/line/line.go index 3149fd96d..e5b46e3fc 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -59,33 +59,33 @@ func (h *handler) Initialize(s courier.Server) error { return nil } -// { -// "events": [ -// { -// "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA", -// "type": "message", -// "timestamp": 1462629479859, -// "source": { -// "type": "user", -// "userId": "U4af4980629..." -// }, -// "message": { -// "id": "325708", -// "type": "text", -// "text": "Hello, world" -// } -// }, -// { -// "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA", -// "type": "follow", -// "timestamp": 1462629479859, -// "source": { -// "type": "user", -// "userId": "U4af4980629..." -// } -// } -// ] -// } +// { +// "events": [ +// { +// "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA", +// "type": "message", +// "timestamp": 1462629479859, +// "source": { +// "type": "user", +// "userId": "U4af4980629..." +// }, +// "message": { +// "id": "325708", +// "type": "text", +// "text": "Hello, world" +// } +// }, +// { +// "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA", +// "type": "follow", +// "timestamp": 1462629479859, +// "source": { +// "type": "user", +// "userId": "U4af4980629..." +// } +// } +// ] +// } type moPayload struct { Events []struct { ReplyToken string `json:"replyToken"` @@ -112,7 +112,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { err := h.validateSignature(channel, r) if err != nil { return nil, err diff --git a/handlers/m3tech/m3tech.go b/handlers/m3tech/m3tech.go index b6ee072f5..7033a014c 100644 --- a/handlers/m3tech/m3tech.go +++ b/handlers/m3tech/m3tech.go @@ -38,7 +38,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveMessage takes care of handling incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, err) diff --git a/handlers/macrokiosk/macrokiosk.go b/handlers/macrokiosk/macrokiosk.go index 045785990..c01b57bfa 100644 --- a/handlers/macrokiosk/macrokiosk.go +++ b/handlers/macrokiosk/macrokiosk.go @@ -61,7 +61,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -89,7 +89,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { diff --git a/handlers/mblox/mblox.go b/handlers/mblox/mblox.go index 70ed01cf3..f049f0d06 100644 --- a/handlers/mblox/mblox.go +++ b/handlers/mblox/mblox.go @@ -60,7 +60,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveEvent is our HTTP handler function for incoming messages -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &eventPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { diff --git a/handlers/mtarget/mtarget.go b/handlers/mtarget/mtarget.go index 70a7143b8..85d45b3f2 100644 --- a/handlers/mtarget/mtarget.go +++ b/handlers/mtarget/mtarget.go @@ -52,7 +52,7 @@ func (h *handler) Initialize(s courier.Server) error { } // ReceiveMsg handles both MO messages and Stop commands -func (h *handler) receiveMsg(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMsg(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, err) diff --git a/handlers/nexmo/nexmo.go b/handlers/nexmo/nexmo.go index a01b6d4e3..ee6e46951 100644 --- a/handlers/nexmo/nexmo.go +++ b/handlers/nexmo/nexmo.go @@ -70,7 +70,7 @@ var statusMappings = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &statusForm{} handlers.DecodeAndValidateForm(form, r) @@ -96,7 +96,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} handlers.DecodeAndValidateForm(form, r) diff --git a/handlers/novo/novo.go b/handlers/novo/novo.go index be3e1af92..84cf820bf 100644 --- a/handlers/novo/novo.go +++ b/handlers/novo/novo.go @@ -45,7 +45,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // check authentication secret := c.StringConfigForKey(courier.ConfigSecret, "") if secret != "" { diff --git a/handlers/playmobile/playmobile.go b/handlers/playmobile/playmobile.go index 331ca1183..69835dc34 100644 --- a/handlers/playmobile/playmobile.go +++ b/handlers/playmobile/playmobile.go @@ -92,7 +92,7 @@ type mtResponse struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &mtResponse{} err := handlers.DecodeAndValidateXML(payload, r) diff --git a/handlers/plivo/plivo.go b/handlers/plivo/plivo.go index 677abae18..bc1d6d6d7 100644 --- a/handlers/plivo/plivo.go +++ b/handlers/plivo/plivo.go @@ -70,7 +70,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -104,7 +104,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { diff --git a/handlers/rocketchat/rocketchat.go b/handlers/rocketchat/rocketchat.go index cf9847935..9ec97088d 100644 --- a/handlers/rocketchat/rocketchat.go +++ b/handlers/rocketchat/rocketchat.go @@ -57,7 +57,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // check authorization secret := channel.StringConfigForKey(configSecret, "") if fmt.Sprintf("Token %s", secret) != r.Header.Get("Authorization") { diff --git a/handlers/shaqodoon/shaqodoon.go b/handlers/shaqodoon/shaqodoon.go index c4beb87f2..7ed8989c5 100644 --- a/handlers/shaqodoon/shaqodoon.go +++ b/handlers/shaqodoon/shaqodoon.go @@ -45,7 +45,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index c3bd2ec76..4a8cdb38f 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -62,7 +62,7 @@ func handleURLVerification(ctx context.Context, channel courier.Channel, w http. return nil, nil } -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { diff --git a/handlers/smscentral/smscentral.go b/handlers/smscentral/smscentral.go index 8847c3258..58a282839 100644 --- a/handlers/smscentral/smscentral.go +++ b/handlers/smscentral/smscentral.go @@ -43,7 +43,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { diff --git a/handlers/start/start.go b/handlers/start/start.go index bb63b88e1..cc0cad359 100644 --- a/handlers/start/start.go +++ b/handlers/start/start.go @@ -56,7 +56,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateXML(payload, r) if err != nil { diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index 81eaaaee6..22fffaabc 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -49,7 +49,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { diff --git a/handlers/telesom/telesom.go b/handlers/telesom/telesom.go index ca42e49d0..5fad540ff 100644 --- a/handlers/telesom/telesom.go +++ b/handlers/telesom/telesom.go @@ -44,7 +44,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { diff --git a/handlers/thinq/thinq.go b/handlers/thinq/thinq.go index f3e351ee6..100e3fae0 100644 --- a/handlers/thinq/thinq.go +++ b/handlers/thinq/thinq.go @@ -55,7 +55,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -103,7 +103,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index 957bcc477..8760dc470 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -100,7 +100,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { err := h.validateSignature(channel, r) if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) @@ -140,7 +140,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { err := h.validateSignature(channel, r) if err != nil { return nil, err diff --git a/handlers/twitter/twitter.go b/handlers/twitter/twitter.go index 05574959e..35cb8b238 100644 --- a/handlers/twitter/twitter.go +++ b/handlers/twitter/twitter.go @@ -65,7 +65,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveVerify handles Twitter's webhook verification callback -func (h *handler) receiveVerify(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveVerify(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { crcToken := r.URL.Query().Get("crc_token") if crcToken == "" { return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, fmt.Errorf(`missing required 'crc_token' query parameter`)) @@ -90,26 +90,26 @@ type moUser struct { ScreenName string `json:"screen_name" validate:"required"` } -// { -// "direct_message_events": [ -// { -// "created_timestamp": "1494877823220", -// "message_create": { -// "message_data": { -// "text": "hello world!", -// }, -// "sender_id": "twitterid1", -// "target": {"recipient_id": "twitterid2" } -// }, -// "type": "message_create", -// "id": "twitterMsgId" -// } -// ], -// "users": { -// "twitterid1": { "id": "twitterid1", "name": "joe", "screen_name": "joe" }, -// "twitterid2": { "id": "twitterid2", "name": "jane", "screen_name": "jane" }, -// } -// } +// { +// "direct_message_events": [ +// { +// "created_timestamp": "1494877823220", +// "message_create": { +// "message_data": { +// "text": "hello world!", +// }, +// "sender_id": "twitterid1", +// "target": {"recipient_id": "twitterid2" } +// }, +// "type": "message_create", +// "id": "twitterMsgId" +// } +// ], +// "users": { +// "twitterid1": { "id": "twitterid1", "name": "joe", "screen_name": "joe" }, +// "twitterid2": { "id": "twitterid2", "name": "jane", "screen_name": "jane" }, +// } +// } type moPayload struct { DirectMessageEvents []struct { CreatedTimestamp string `json:"created_timestamp" validate:"required"` @@ -134,7 +134,7 @@ type moPayload struct { } // receiveEvent is our HTTP handler function for incoming events -func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // read our handle id handleID := c.StringConfigForKey(configHandleID, "") if handleID == "" { @@ -204,25 +204,25 @@ func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.Re return handlers.WriteMsgsAndResponse(ctx, h, msgs, w, r) } -// { -// "event": { -// "type": "message_create", -// "message_create": { -// "target": { -// "recipient_id": "844385345234" -// }, -// "message_data": { -// "text": "Hello World!", -// "quick_reply": { -// "type": "options", -// "options": [ -// { "label": "Red"}, {"label": "Green"} -// ] -// } -// } -// } -// } -// } +// { +// "event": { +// "type": "message_create", +// "message_create": { +// "target": { +// "recipient_id": "844385345234" +// }, +// "message_data": { +// "text": "Hello World!", +// "quick_reply": { +// "type": "options", +// "options": [ +// { "label": "Red"}, {"label": "Green"} +// ] +// } +// } +// } +// } +// } type mtPayload struct { Event struct { Type string `json:"type"` diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index 429dd611c..6f4c571e2 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -89,7 +89,7 @@ type welcomeMessagePayload struct { } // receiveEvent is our HTTP handler function for incoming messages -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { err := h.validateSignature(channel, r) if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) diff --git a/handlers/vk/vk.go b/handlers/vk/vk.go index 3a0830940..fc357d743 100644 --- a/handlers/vk/vk.go +++ b/handlers/vk/vk.go @@ -193,7 +193,7 @@ type mediaUploadInfoPayload struct { } // receiveEvent handles request event type -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // read request body bodyBytes, err := ioutil.ReadAll(io.LimitReader(r.Body, 100000)) diff --git a/handlers/wavy/wavy.go b/handlers/wavy/wavy.go index 5b02ca819..87b215fc3 100644 --- a/handlers/wavy/wavy.go +++ b/handlers/wavy/wavy.go @@ -62,7 +62,7 @@ type sentStatusPayload struct { } // sentStatusMessage is our HTTP handler function for status updates -func (h *handler) sentStatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) sentStatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &sentStatusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -85,7 +85,7 @@ type deliveredStatusPayload struct { } // sentStatusMessage is our HTTP handler function for status updates -func (h *handler) deliveredStatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) deliveredStatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &deliveredStatusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -111,7 +111,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index e02bf1888..69c8e5eac 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -61,7 +61,7 @@ type verifyForm struct { } // VerifyURL is our HTTP handler function for WeChat config URL verification callbacks -func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &verifyForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -170,7 +170,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateXML(payload, r) if err != nil { diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index e43902aa0..5d9ccd4c5 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -172,7 +172,7 @@ type eventPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { payload := &eventPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { diff --git a/handlers/yo/yo.go b/handlers/yo/yo.go index 84d0f7b3d..eb8ed4f9d 100644 --- a/handlers/yo/yo.go +++ b/handlers/yo/yo.go @@ -53,7 +53,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { diff --git a/handlers/zenvia/zenvia.go b/handlers/zenvia/zenvia.go index 97eb289b7..4b2c5ded8 100644 --- a/handlers/zenvia/zenvia.go +++ b/handlers/zenvia/zenvia.go @@ -76,7 +76,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // get our params payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) @@ -156,7 +156,7 @@ type statusPayload struct { } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // get our params payload := &statusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) @@ -176,10 +176,8 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w // write our status status := h.Backend().NewMsgStatusForExternalID(channel, payload.MessageID, msgStatus) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) - } -// type mtContent struct { Type string `json:"type"` Text string `json:"text,omitempty"` diff --git a/handlers/zenviaold/zenviaold.go b/handlers/zenviaold/zenviaold.go index f0093bade..d376931e3 100644 --- a/handlers/zenviaold/zenviaold.go +++ b/handlers/zenviaold/zenviaold.go @@ -40,17 +40,17 @@ func (h *handler) Initialize(s courier.Server) error { return nil } -// { -// "callbackMoRequest": { -// "id": "20690090", -// "mobile": "555191951711", -// "shortCode": "40001", -// "account": "zenvia.envio", -// "body": "Content of reply SMS", -// "received": "2014-08-26T12:27:08.488-03:00", -// "correlatedMessageSmsId": "hs765939061" -// } -// } +// { +// "callbackMoRequest": { +// "id": "20690090", +// "mobile": "555191951711", +// "shortCode": "40001", +// "account": "zenvia.envio", +// "body": "Content of reply SMS", +// "received": "2014-08-26T12:27:08.488-03:00", +// "correlatedMessageSmsId": "hs765939061" +// } +// } type moPayload struct { CallbackMORequest struct { ID string `json:"id" validate:"required" ` @@ -61,17 +61,17 @@ type moPayload struct { } `json:"callbackMoRequest"` } -// { -// "callbackMtRequest": { -// "status": "03", -// "statusMessage": "Delivered", -// "statusDetail": "120", -// "statusDetailMessage": "Message received by mobile", -// "id": "hs765939216", -// "received": "2014-08-26T12:55:48.593-03:00", -// "mobileOperatorName": "Claro" -// } -// } +// { +// "callbackMtRequest": { +// "status": "03", +// "statusMessage": "Delivered", +// "statusDetail": "120", +// "statusDetailMessage": "Message received by mobile", +// "id": "hs765939216", +// "received": "2014-08-26T12:55:48.593-03:00", +// "mobileOperatorName": "Claro" +// } +// } type statusPayload struct { CallbackMTRequest struct { StatusCode string `json:"status" validate:"required"` @@ -79,16 +79,16 @@ type statusPayload struct { } } -// { -// "sendSmsRequest": { -// "to": "555199999999", -// "schedule": "2014-08-22T14:55:00", -// "msg": "Test message.", -// "callbackOption": "NONE", -// "id": "002", -// "aggregateId": "1111" -// } -// } +// { +// "sendSmsRequest": { +// "to": "555199999999", +// "schedule": "2014-08-22T14:55:00", +// "msg": "Test message.", +// "callbackOption": "NONE", +// "id": "002", +// "aggregateId": "1111" +// } +// } type mtPayload struct { SendSMSRequest struct { To string `json:"to"` @@ -115,7 +115,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // get our params payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) @@ -143,7 +143,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { // get our params payload := &statusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) diff --git a/server.go b/server.go index b98c9c5a3..6d98d406f 100644 --- a/server.go +++ b/server.go @@ -299,7 +299,9 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe } }() - events, err := handlerFunc(ctx, channel, recorder.ResponseWriter, r) + logger := NewChannelLoggerForReceive(channel) + + events, err := handlerFunc(ctx, channel, recorder.ResponseWriter, r, logger) duration := time.Since(start) secondDuration := float64(duration) / float64(time.Second) From c95273fca103603ce0ff82f179c404299a3bba0c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 23 Aug 2022 11:59:17 -0500 Subject: [PATCH 088/294] Use logger for handler func calls --- backends/rapidpro/contact.go | 2 +- channel_log.go | 69 +++++++++++++++-------- handlers/facebook/facebook_test.go | 2 +- handlers/facebookapp/facebookapp_test.go | 6 +- handlers/jiochat/jiochat_test.go | 2 +- handlers/slack/slack_test.go | 2 +- handlers/vk/vk_test.go | 2 +- handlers/wechat/wechat_test.go | 2 +- server.go | 72 ++++++++++++------------ 9 files changed, 89 insertions(+), 70 deletions(-) diff --git a/backends/rapidpro/contact.go b/backends/rapidpro/contact.go index 373621ba5..d0b91f2a0 100644 --- a/backends/rapidpro/contact.go +++ b/backends/rapidpro/contact.go @@ -140,7 +140,7 @@ func contactForURN(ctx context.Context, b *backend, org OrgID, channel *DBChanne describer, isDescriber := handler.(courier.URNDescriber) if isDescriber { // TODO: this should be created by the server and passed down - logger := courier.NewChannelLoggerForReceive(channel) + logger := courier.NewChannelLogger(channel) atts, err := describer.DescribeURN(ctx, channel, urn, logger) diff --git a/channel_log.go b/channel_log.go index f81fc5082..1535f3d7a 100644 --- a/channel_log.go +++ b/channel_log.go @@ -92,17 +92,19 @@ type ChannelLog struct { type ChannelLogType string const ( - ChannelLogTypeMessageSend ChannelLogType = "message_send" - ChannelLogTypeMessageReceive ChannelLogType = "message_receive" + ChannelLogTypeUnknown ChannelLogType = "unknown" + ChannelLogTypeMsgSend ChannelLogType = "msg_send" + ChannelLogTypeMsgStatus ChannelLogType = "msg_status" + ChannelLogTypeMsgReceive ChannelLogType = "msg_receive" + ChannelLogTypeEventReceive ChannelLogType = "event_receive" ) var logTypeDescriptions = map[ChannelLogType]string{ - ChannelLogTypeMessageSend: "Message Send", - ChannelLogTypeMessageReceive: "Message Receive", -} -var logTypeErrorDescriptions = map[ChannelLogType]string{ - ChannelLogTypeMessageSend: "Message Sending Error", - ChannelLogTypeMessageReceive: "Message Receive Error", + ChannelLogTypeUnknown: "Other Event", + ChannelLogTypeMsgSend: "Message Send", + ChannelLogTypeMsgStatus: "Message Status", + ChannelLogTypeMsgReceive: "Message Receive", + ChannelLogTypeEventReceive: "Event Receive", } type ChannelLogger struct { @@ -110,39 +112,56 @@ type ChannelLogger struct { channel Channel msgID MsgID + traces []*httpx.Trace errors []string logs []*ChannelLog } func NewChannelLoggerForSend(msg Msg) *ChannelLogger { - return &ChannelLogger{type_: ChannelLogTypeMessageSend, channel: msg.Channel(), msgID: msg.ID()} + return &ChannelLogger{type_: ChannelLogTypeMsgSend, channel: msg.Channel(), msgID: msg.ID()} } -func NewChannelLoggerForReceive(channel Channel) *ChannelLogger { - return &ChannelLogger{type_: ChannelLogTypeMessageReceive, channel: channel} +func NewChannelLogger(channel Channel) *ChannelLogger { + return &ChannelLogger{type_: ChannelLogTypeUnknown, channel: channel} } -// HTTP logs an HTTP request and response -func (l *ChannelLogger) HTTP(t *httpx.Trace) { - var description string - if t.Response == nil || t.Response.StatusCode/100 != 2 { - description = logTypeErrorDescriptions[l.type_] - } else { - description = logTypeDescriptions[l.type_] +func (l *ChannelLogger) SetType(t ChannelLogType) { + l.type_ = t +} + +func (l *ChannelLogger) SetMsgID(id MsgID) { + l.msgID = id +} + +// Recorder logs a recording of an incoming HTTP request +func (l *ChannelLogger) Recorder(r *httpx.Recorder) { + // prepend so it's the first HTTP request in the log + l.traces = append([]*httpx.Trace{r.Trace}, l.traces...) + + if l.channel != nil { + l.logs = append(l.logs, NewChannelLogFromTrace(logTypeDescriptions[l.type_], l.channel, l.msgID, r.Trace)) } +} - l.logs = append(l.logs, NewChannelLogFromTrace(description, l.channel, l.msgID, t)) +// HTTP logs an outgoing HTTP request and response +func (l *ChannelLogger) HTTP(t *httpx.Trace) { + l.traces = append(l.traces, t) + + if l.channel != nil { + l.logs = append(l.logs, NewChannelLogFromTrace(logTypeDescriptions[l.type_], l.channel, l.msgID, t)) + } } func (l *ChannelLogger) Error(err error) { l.errors = append(l.errors, err.Error()) - // if we have an existing log which isn't already an error, update it - if len(l.logs) > 0 && l.logs[len(l.logs)-1].Error == "" { - l.logs[len(l.logs)-1].Error = err.Error() - l.logs[len(l.logs)-1].Description = logTypeErrorDescriptions[l.type_] - } else { - l.logs = append(l.logs, NewChannelLogFromError(logTypeErrorDescriptions[l.type_], l.channel, l.msgID, 0, err)) + if l.channel != nil { + // if we have an existing log which isn't already an error, update it + if len(l.logs) > 0 && l.logs[len(l.logs)-1].Error == "" { + l.logs[len(l.logs)-1].Error = err.Error() + } else { + l.logs = append(l.logs, NewChannelLogFromError(logTypeDescriptions[l.type_], l.channel, l.msgID, 0, err)) + } } } diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index bf6abe798..65befa26b 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -495,7 +495,7 @@ func TestDescribe(t *testing.T) { channel := testChannels[0] handler := newHandler().(courier.URNDescriber) - logger := courier.NewChannelLoggerForReceive(channel) + logger := courier.NewChannelLogger(channel) tcs := []struct { urn urns.URN diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 09c62d026..ca5260315 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -191,7 +191,7 @@ func TestDescribeFBA(t *testing.T) { channel := testChannelsFBA[0] handler := newHandler("FBA", "Facebook", false).(courier.URNDescriber) - logger := courier.NewChannelLoggerForReceive(channel) + logger := courier.NewChannelLogger(channel) tcs := []struct { urn urns.URN @@ -214,7 +214,7 @@ func TestDescribeIG(t *testing.T) { channel := testChannelsIG[0] handler := newHandler("IG", "Instagram", false).(courier.URNDescriber) - logger := courier.NewChannelLoggerForReceive(channel) + logger := courier.NewChannelLogger(channel) tcs := []struct { urn urns.URN @@ -233,7 +233,7 @@ func TestDescribeIG(t *testing.T) { func TestDescribeWAC(t *testing.T) { channel := testChannelsWAC[0] handler := newHandler("WAC", "Cloud API WhatsApp", false).(courier.URNDescriber) - logger := courier.NewChannelLoggerForReceive(channel) + logger := courier.NewChannelLogger(channel) tcs := []struct { urn urns.URN diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index b541a3bc6..bc4cde5c7 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -272,7 +272,7 @@ func TestDescribeURN(t *testing.T) { s := newServer(mb) handler := &handler{handlers.NewBaseHandler(courier.ChannelType("JC"), "Jiochat")} handler.Initialize(s) - logger := courier.NewChannelLoggerForReceive(testChannels[0]) + logger := courier.NewChannelLogger(testChannels[0]) tcs := []struct { urn urns.URN diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index e88b1b40f..2937e56c8 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -360,7 +360,7 @@ func TestDescribeURN(t *testing.T) { defer server.Close() handler := newHandler().(courier.URNDescriber) - logger := courier.NewChannelLoggerForReceive(testChannels[0]) + logger := courier.NewChannelLogger(testChannels[0]) urn, _ := urns.NewURNFromParts(urns.SlackScheme, "U012345", "", "") data := map[string]string{"name": "dummy user"} diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index 6675682da..05a59d5d7 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -374,7 +374,7 @@ func TestDescribeURN(t *testing.T) { defer server.Close() handler := newHandler().(courier.URNDescriber) - logger := courier.NewChannelLoggerForReceive(testChannels[0]) + logger := courier.NewChannelLogger(testChannels[0]) urn, _ := urns.NewURNFromParts(urns.VKScheme, "123456789", "", "") data := map[string]string{"name": "John Doe"} diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index 808ed5df1..57651308d 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -268,7 +268,7 @@ func TestDescribe(t *testing.T) { s := newServer(mb) handler := &handler{handlers.NewBaseHandler(courier.ChannelType("WC"), "WeChat")} handler.Initialize(s) - logger := courier.NewChannelLoggerForReceive(testChannels[0]) + logger := courier.NewChannelLogger(testChannels[0]) tcs := []struct { urn urns.URN diff --git a/server.go b/server.go index 6d98d406f..6adb3e22b 100644 --- a/server.go +++ b/server.go @@ -275,6 +275,7 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe defer cancel() r = r.WithContext(ctx) + // get the channel for this request - can be nil, e.g. FBA verification requests channel, err := handler.GetChannel(ctx, r) if err != nil { WriteError(ctx, w, r, err) @@ -287,8 +288,6 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe return } - logs := make([]*ChannelLog, 0, 1) - defer func() { // catch any panics and recover panicLog := recover() @@ -299,16 +298,16 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe } }() - logger := NewChannelLoggerForReceive(channel) + logger := NewChannelLogger(channel) - events, err := handlerFunc(ctx, channel, recorder.ResponseWriter, r, logger) + events, hErr := handlerFunc(ctx, channel, recorder.ResponseWriter, r, logger) duration := time.Since(start) secondDuration := float64(duration) / float64(time.Second) // if we received an error, write it out and report it - if err != nil { - logrus.WithError(err).WithField("channel_uuid", channel.UUID()).WithField("request", string(recorder.Trace.RequestTrace)).Error("error handling request") - writeAndLogRequestError(ctx, recorder.ResponseWriter, r, channel, err) + if hErr != nil { + logrus.WithError(hErr).WithField("channel_uuid", channel.UUID()).WithField("request", string(recorder.Trace.RequestTrace)).Error("error handling request") + writeAndLogRequestError(ctx, recorder.ResponseWriter, r, channel, hErr) } // end recording of the request so that we have a response trace @@ -317,39 +316,40 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe writeAndLogRequestError(ctx, w, r, channel, err) } - // if we have a channel matched but no events were created we still want to log this to the channel, do so - if channel != nil && len(events) == 0 { - if err != nil { - logs = append(logs, NewChannelLogFromTrace("Channel Error", channel, NilMsgID, recorder.Trace).WithError("Channel Error", err)) - analytics.Gauge(fmt.Sprintf("courier.channel_error_%s", channel.ChannelType()), secondDuration) - } else { - logs = append(logs, NewChannelLogFromTrace("Request Ignored", channel, NilMsgID, recorder.Trace)) - analytics.Gauge(fmt.Sprintf("courier.channel_ignored_%s", channel.ChannelType()), secondDuration) + logger.Recorder(recorder) + + if channel != nil { + // if we have a channel but no events were created, we still log this to analytics + if len(events) == 0 { + if hErr != nil { + analytics.Gauge(fmt.Sprintf("courier.channel_error_%s", channel.ChannelType()), secondDuration) + } else { + analytics.Gauge(fmt.Sprintf("courier.channel_ignored_%s", channel.ChannelType()), secondDuration) + } } - } - // otherwise, log the request for each message - for _, event := range events { - switch e := event.(type) { - case Msg: - logs = append(logs, NewChannelLogFromTrace("Message Receive", channel, e.ID(), recorder.Trace).WithError("Message Receive", err)) - analytics.Gauge(fmt.Sprintf("courier.msg_receive_%s", channel.ChannelType()), secondDuration) - LogMsgReceived(r, e) - case ChannelEvent: - logs = append(logs, NewChannelLogFromTrace("Event Receive", channel, NilMsgID, recorder.Trace).WithError("Event Receive", err)) - analytics.Gauge(fmt.Sprintf("courier.evt_receive_%s", channel.ChannelType()), secondDuration) - LogChannelEventReceived(r, e) - case MsgStatus: - logs = append(logs, NewChannelLogFromTrace("Status Update", channel, e.ID(), recorder.Trace).WithError("Status Update", err)) - analytics.Gauge(fmt.Sprintf("courier.msg_status_%s", channel.ChannelType()), secondDuration) - LogMsgStatusReceived(r, e) + for _, event := range events { + switch e := event.(type) { + case Msg: + logger.SetMsgID(e.ID()) + logger.SetType(ChannelLogTypeMsgReceive) + analytics.Gauge(fmt.Sprintf("courier.msg_receive_%s", channel.ChannelType()), secondDuration) + LogMsgReceived(r, e) + case MsgStatus: + logger.SetMsgID(e.ID()) + logger.SetType(ChannelLogTypeMsgStatus) + analytics.Gauge(fmt.Sprintf("courier.msg_status_%s", channel.ChannelType()), secondDuration) + LogMsgStatusReceived(r, e) + case ChannelEvent: + logger.SetType(ChannelLogTypeEventReceive) + analytics.Gauge(fmt.Sprintf("courier.evt_receive_%s", channel.ChannelType()), secondDuration) + LogChannelEventReceived(r, e) + } } - } - // and write these out, logging if there's an error - err = s.backend.WriteChannelLogs(ctx, logs) - if err != nil { - logrus.WithError(err).Error("error writing channel log") + if err := s.backend.WriteChannelLogs(ctx, logger.Logs()); err != nil { + logrus.WithError(err).Error("error writing channel log") + } } } } From adeb54b0079d81991f9c7fcdaa7900e30156fe26 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 23 Aug 2022 13:17:17 -0500 Subject: [PATCH 089/294] Add type to ChannelLogger constructor --- backends/rapidpro/contact.go | 2 +- channel_log.go | 4 ++-- handlers/facebook/facebook_test.go | 2 +- handlers/facebookapp/facebookapp_test.go | 6 +++--- handlers/jiochat/jiochat_test.go | 2 +- handlers/slack/slack_test.go | 2 +- handlers/vk/vk_test.go | 2 +- handlers/wechat/wechat_test.go | 2 +- server.go | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/backends/rapidpro/contact.go b/backends/rapidpro/contact.go index d0b91f2a0..945806577 100644 --- a/backends/rapidpro/contact.go +++ b/backends/rapidpro/contact.go @@ -140,7 +140,7 @@ func contactForURN(ctx context.Context, b *backend, org OrgID, channel *DBChanne describer, isDescriber := handler.(courier.URNDescriber) if isDescriber { // TODO: this should be created by the server and passed down - logger := courier.NewChannelLogger(channel) + logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, channel) atts, err := describer.DescribeURN(ctx, channel, urn, logger) diff --git a/channel_log.go b/channel_log.go index 1535f3d7a..3d5a2f05c 100644 --- a/channel_log.go +++ b/channel_log.go @@ -121,8 +121,8 @@ func NewChannelLoggerForSend(msg Msg) *ChannelLogger { return &ChannelLogger{type_: ChannelLogTypeMsgSend, channel: msg.Channel(), msgID: msg.ID()} } -func NewChannelLogger(channel Channel) *ChannelLogger { - return &ChannelLogger{type_: ChannelLogTypeUnknown, channel: channel} +func NewChannelLogger(t ChannelLogType, channel Channel) *ChannelLogger { + return &ChannelLogger{type_: t, channel: channel} } func (l *ChannelLogger) SetType(t ChannelLogType) { diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index 65befa26b..94b925f3c 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -495,7 +495,7 @@ func TestDescribe(t *testing.T) { channel := testChannels[0] handler := newHandler().(courier.URNDescriber) - logger := courier.NewChannelLogger(channel) + logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, channel) tcs := []struct { urn urns.URN diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index ca5260315..d35c40787 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -191,7 +191,7 @@ func TestDescribeFBA(t *testing.T) { channel := testChannelsFBA[0] handler := newHandler("FBA", "Facebook", false).(courier.URNDescriber) - logger := courier.NewChannelLogger(channel) + logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, channel) tcs := []struct { urn urns.URN @@ -214,7 +214,7 @@ func TestDescribeIG(t *testing.T) { channel := testChannelsIG[0] handler := newHandler("IG", "Instagram", false).(courier.URNDescriber) - logger := courier.NewChannelLogger(channel) + logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, channel) tcs := []struct { urn urns.URN @@ -233,7 +233,7 @@ func TestDescribeIG(t *testing.T) { func TestDescribeWAC(t *testing.T) { channel := testChannelsWAC[0] handler := newHandler("WAC", "Cloud API WhatsApp", false).(courier.URNDescriber) - logger := courier.NewChannelLogger(channel) + logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, channel) tcs := []struct { urn urns.URN diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index bc4cde5c7..5852eb317 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -272,7 +272,7 @@ func TestDescribeURN(t *testing.T) { s := newServer(mb) handler := &handler{handlers.NewBaseHandler(courier.ChannelType("JC"), "Jiochat")} handler.Initialize(s) - logger := courier.NewChannelLogger(testChannels[0]) + logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, testChannels[0]) tcs := []struct { urn urns.URN diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 2937e56c8..f796de582 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -360,7 +360,7 @@ func TestDescribeURN(t *testing.T) { defer server.Close() handler := newHandler().(courier.URNDescriber) - logger := courier.NewChannelLogger(testChannels[0]) + logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, testChannels[0]) urn, _ := urns.NewURNFromParts(urns.SlackScheme, "U012345", "", "") data := map[string]string{"name": "dummy user"} diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index 05a59d5d7..9929e8ece 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -374,7 +374,7 @@ func TestDescribeURN(t *testing.T) { defer server.Close() handler := newHandler().(courier.URNDescriber) - logger := courier.NewChannelLogger(testChannels[0]) + logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, testChannels[0]) urn, _ := urns.NewURNFromParts(urns.VKScheme, "123456789", "", "") data := map[string]string{"name": "John Doe"} diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index 57651308d..54bf92e00 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -268,7 +268,7 @@ func TestDescribe(t *testing.T) { s := newServer(mb) handler := &handler{handlers.NewBaseHandler(courier.ChannelType("WC"), "WeChat")} handler.Initialize(s) - logger := courier.NewChannelLogger(testChannels[0]) + logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, testChannels[0]) tcs := []struct { urn urns.URN diff --git a/server.go b/server.go index 6adb3e22b..478c1a796 100644 --- a/server.go +++ b/server.go @@ -298,7 +298,7 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe } }() - logger := NewChannelLogger(channel) + logger := NewChannelLogger(ChannelLogTypeUnknown, channel) events, hErr := handlerFunc(ctx, channel, recorder.ResponseWriter, r, logger) duration := time.Since(start) From 9f92a2619c3495e1f66370c4f1895d19390d4f24 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 23 Aug 2022 13:47:13 -0500 Subject: [PATCH 090/294] Replace last handler usages of raw channel logs --- channel_log.go | 7 ++++--- handlers/jiochat/jiochat.go | 29 ++++++++++------------------- handlers/slack/slack.go | 14 ++++++-------- handlers/telegram/telegram.go | 24 +++++++++++------------- handlers/wechat/wechat.go | 22 +++++++++------------- 5 files changed, 40 insertions(+), 56 deletions(-) diff --git a/channel_log.go b/channel_log.go index 3d5a2f05c..0bfd00efa 100644 --- a/channel_log.go +++ b/channel_log.go @@ -45,8 +45,7 @@ func NewChannelLogFromTrace(description string, channel Channel, msgID MsgID, tr return log } -// NewChannelLogFromError creates a new channel log for the passed in channel, msg id and error -func NewChannelLogFromError(description string, channel Channel, msgID MsgID, elapsed time.Duration, err error) *ChannelLog { +func newChannelLogFromError(description string, channel Channel, msgID MsgID, elapsed time.Duration, err error) *ChannelLog { return &ChannelLog{ Description: description, Channel: channel, @@ -97,6 +96,7 @@ const ( ChannelLogTypeMsgStatus ChannelLogType = "msg_status" ChannelLogTypeMsgReceive ChannelLogType = "msg_receive" ChannelLogTypeEventReceive ChannelLogType = "event_receive" + ChannelLogTypeTokenFetch ChannelLogType = "token_fetch" ) var logTypeDescriptions = map[ChannelLogType]string{ @@ -105,6 +105,7 @@ var logTypeDescriptions = map[ChannelLogType]string{ ChannelLogTypeMsgStatus: "Message Status", ChannelLogTypeMsgReceive: "Message Receive", ChannelLogTypeEventReceive: "Event Receive", + ChannelLogTypeTokenFetch: "Token Fetch", } type ChannelLogger struct { @@ -160,7 +161,7 @@ func (l *ChannelLogger) Error(err error) { if len(l.logs) > 0 && l.logs[len(l.logs)-1].Error == "" { l.logs[len(l.logs)-1].Error = err.Error() } else { - l.logs = append(l.logs, NewChannelLogFromError(logTypeDescriptions[l.type_], l.channel, l.msgID, 0, err)) + l.logs = append(l.logs, newChannelLogFromError(logTypeDescriptions[l.type_], l.channel, l.msgID, 0, err)) } } } diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 7b0c57158..a55a69696 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -18,6 +18,7 @@ import ( "github.com/gomodule/redigo/redis" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/jsonx" "github.com/nyaruka/gocommon/urns" "github.com/sirupsen/logrus" ) @@ -71,7 +72,7 @@ func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http } dictOrder := []string{channel.StringConfigForKey(configAppSecret, ""), form.Timestamp, form.Nonce} - sort.Sort(sort.StringSlice(dictOrder)) + sort.Strings(dictOrder) combinedParams := strings.Join(dictOrder, "") @@ -167,41 +168,31 @@ type fetchPayload struct { // fetchAccessToken tries to fetch a new token for our channel, setting the result in redis func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) error { - start := time.Now() - logs := make([]*courier.ChannelLog, 0, 1) + logger := courier.NewChannelLogger(courier.ChannelLogTypeTokenFetch, channel) tokenURL, _ := url.Parse(fmt.Sprintf("%s/%s", sendURL, "auth/token.action")) - payload := &fetchPayload{ GrantType: "client_credentials", ClientID: channel.StringConfigForKey(configAppID, ""), ClientSecret: channel.StringConfigForKey(configAppSecret, ""), } - jsonBody, err := json.Marshal(payload) - if err != nil { - return err - } - - req, err := http.NewRequest(http.MethodPost, tokenURL.String(), bytes.NewReader(jsonBody)) + req, err := http.NewRequest(http.MethodPost, tokenURL.String(), bytes.NewReader(jsonx.MustMarshal(payload))) if err != nil { return err } req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - duration := time.Now().Sub(start) - logs = append(logs, courier.NewChannelLogFromError("failed to fetch access token", channel, courier.NilMsgID, duration, err)) - return h.Backend().WriteChannelLogs(ctx, logs) + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return h.Backend().WriteChannelLogs(ctx, logger.Logs()) } - accessToken, err := jsonparser.GetString(trace.ResponseBody, "access_token") + accessToken, err := jsonparser.GetString(respBody, "access_token") if err != nil { - duration := time.Now().Sub(start) - logs = append(logs, courier.NewChannelLogFromError("invalid json", channel, courier.NilMsgID, duration, err)) - return h.Backend().WriteChannelLogs(ctx, logs) + logger.Error(errors.New("access_token not found in response")) + return h.Backend().WriteChannelLogs(ctx, logger.Logs()) } rc := h.Backend().RedisPool().Get() diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index 4a8cdb38f..39a2e28ef 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -85,7 +85,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h attachmentURLs := make([]string, 0) for _, file := range payload.Event.Files { - fileURL, err := h.resolveFile(ctx, channel, file) + fileURL, err := h.resolveFile(ctx, channel, file, logger) if err != nil { courier.LogRequestError(r, channel, err) } else { @@ -105,7 +105,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "Ignoring request, no message") } -func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file File) (string, error) { +func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file File, logger *courier.ChannelLogger) (string, error) { userToken := channel.StringConfigForKey(configUserToken, "") fileApiURL := apiURL + "/files.sharedPublicURL" @@ -119,15 +119,13 @@ func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file req.Header.Add("Content-Type", "application/json; charset=utf-8") req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", userToken)) - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - log := courier.NewChannelLogFromTrace("File Resolving", channel, courier.NilMsgID, trace).WithError("File Resolving Error", err) - h.Backend().WriteChannelLogs(ctx, []*courier.ChannelLog{log}) - return "", err + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return "", errors.New("unable to resolve file") } var fResponse FileResponse - if err := json.Unmarshal(trace.ResponseBody, &fResponse); err != nil { + if err := json.Unmarshal(respBody, &fResponse); err != nil { return "", errors.Errorf("couldn't unmarshal file response: %v", err) } diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index 22fffaabc..5c95b0d0a 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -102,15 +102,15 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } photo = payload.Message.Photo[i] } - mediaURL, err = h.resolveFileID(ctx, channel, photo.FileID) + mediaURL, err = h.resolveFileID(ctx, channel, photo.FileID, logger) } else if payload.Message.Video != nil { - mediaURL, err = h.resolveFileID(ctx, channel, payload.Message.Video.FileID) + mediaURL, err = h.resolveFileID(ctx, channel, payload.Message.Video.FileID, logger) } else if payload.Message.Voice != nil { - mediaURL, err = h.resolveFileID(ctx, channel, payload.Message.Voice.FileID) + mediaURL, err = h.resolveFileID(ctx, channel, payload.Message.Voice.FileID, logger) } else if payload.Message.Sticker != nil { - mediaURL, err = h.resolveFileID(ctx, channel, payload.Message.Sticker.Thumb.FileID) + mediaURL, err = h.resolveFileID(ctx, channel, payload.Message.Sticker.Thumb.FileID, logger) } else if payload.Message.Document != nil { - mediaURL, err = h.resolveFileID(ctx, channel, payload.Message.Document.FileID) + mediaURL, err = h.resolveFileID(ctx, channel, payload.Message.Document.FileID, logger) } else if payload.Message.Venue != nil { text = utils.JoinNonEmpty(", ", payload.Message.Venue.Title, payload.Message.Venue.Address) mediaURL = fmt.Sprintf("geo:%f,%f", payload.Message.Location.Latitude, payload.Message.Location.Longitude) @@ -324,7 +324,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return status, nil } -func (h *handler) resolveFileID(ctx context.Context, channel courier.Channel, fileID string) (string, error) { +func (h *handler) resolveFileID(ctx context.Context, channel courier.Channel, fileID string, logger *courier.ChannelLogger) (string, error) { confAuth := channel.ConfigForKey(courier.ConfigAuthToken, "") authToken, isStr := confAuth.(string) if !isStr || authToken == "" { @@ -343,15 +343,13 @@ func (h *handler) resolveFileID(ctx context.Context, channel courier.Channel, fi courier.LogRequestError(req, channel, err) } - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - log := courier.NewChannelLogFromTrace("File Resolving", channel, courier.NilMsgID, trace).WithError("File Resolving Error", err) - h.Backend().WriteChannelLogs(ctx, []*courier.ChannelLog{log}) - return "", err + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return "", errors.New("unable to resolve file") } // was this request successful? - ok, err := jsonparser.GetBoolean(trace.ResponseBody, "ok") + ok, err := jsonparser.GetBoolean(respBody, "ok") if err != nil { return "", errors.Errorf("no 'ok' in response") } @@ -361,7 +359,7 @@ func (h *handler) resolveFileID(ctx context.Context, channel courier.Channel, fi } // grab the path for our file - filePath, err := jsonparser.GetString(trace.ResponseBody, "result", "file_path") + filePath, err := jsonparser.GetString(respBody, "result", "file_path") if err != nil { return "", errors.Errorf("no 'result.file_path' in response") } diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index 69c8e5eac..051e3abbc 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -97,15 +97,13 @@ func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http // fetchAccessToken tries to fetch a new token for our channel, setting the result in redis func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) error { - start := time.Now() - logs := make([]*courier.ChannelLog, 0, 1) + logger := courier.NewChannelLogger(courier.ChannelLogTypeTokenFetch, channel) form := url.Values{ "grant_type": []string{"client_credential"}, "appid": []string{channel.StringConfigForKey(configAppID, "")}, "secret": []string{channel.StringConfigForKey(configAppSecret, "")}, } - tokenURL, _ := url.Parse(fmt.Sprintf("%s/%s", sendURL, "token")) tokenURL.RawQuery = form.Encode() @@ -113,20 +111,18 @@ func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - duration := time.Now().Sub(start) - logs = append(logs, courier.NewChannelLogFromError("failed to fetch access token", channel, courier.NilMsgID, duration, err)) - return h.Backend().WriteChannelLogs(ctx, logs) + resp, respBody, err := handlers.RequestHTTP(req, logger) + if err != nil || resp.StatusCode/100 != 2 { + return h.Backend().WriteChannelLogs(ctx, logger.Logs()) } - accessToken, err := jsonparser.GetString(trace.ResponseBody, "access_token") + accessToken, err := jsonparser.GetString(respBody, "access_token") if err != nil { - duration := time.Now().Sub(start) - logs = append(logs, courier.NewChannelLogFromError("invalid json", channel, courier.NilMsgID, duration, err)) - return h.Backend().WriteChannelLogs(ctx, logs) + logger.Error(errors.New("access_token not found in response")) + return h.Backend().WriteChannelLogs(ctx, logger.Logs()) } - expiration, err := jsonparser.GetInt(trace.ResponseBody, "expires_in") + + expiration, err := jsonparser.GetInt(respBody, "expires_in") if err != nil { expiration = 7200 } From 8b025f44e44bdc47f54e09e363eef63a357d063a Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 23 Aug 2022 14:18:27 -0500 Subject: [PATCH 091/294] Change backend WriteChannelLogs to WriteChannelLog which takes a logger --- backend.go | 4 +-- backends/rapidpro/backend.go | 6 ++-- backends/rapidpro/backend_test.go | 2 +- backends/rapidpro/contact.go | 2 +- channel_log.go | 44 ++++++++++++++++-------- channel_log_test.go | 4 +-- handlers/facebook/facebook_test.go | 2 +- handlers/facebookapp/facebookapp_test.go | 6 ++-- handlers/http_test.go | 10 +++--- handlers/jiochat/jiochat.go | 6 ++-- handlers/jiochat/jiochat_test.go | 2 +- handlers/slack/slack_test.go | 2 +- handlers/test.go | 2 +- handlers/vk/vk_test.go | 2 +- handlers/wechat/wechat.go | 6 ++-- handlers/wechat/wechat_test.go | 2 +- sender.go | 4 +-- server.go | 4 +-- test/backend.go | 18 +++++----- 19 files changed, 71 insertions(+), 57 deletions(-) diff --git a/backend.go b/backend.go index 5bc891edd..32ba7fbd5 100644 --- a/backend.go +++ b/backend.go @@ -62,8 +62,8 @@ type Backend interface { // WriteChannelEvent writes the passed in channel even returning any error WriteChannelEvent(context.Context, ChannelEvent) error - // WriteChannelLogs writes the passed in channel logs to our backend - WriteChannelLogs(context.Context, []*ChannelLog) error + // WriteChannelLog writes the passed in channel log to our backend + WriteChannelLog(context.Context, *ChannelLogger) error // PopNextOutgoingMsg returns the next message that needs to be sent, callers should call MarkOutgoingMsgComplete with the // returned message when they have dealt with the message (regardless of whether it was sent or not) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index fb83a3ce4..7a40cb5e2 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -379,12 +379,12 @@ func (b *backend) WriteChannelEvent(ctx context.Context, event courier.ChannelEv return writeChannelEvent(timeout, b, event) } -// WriteChannelLogs persists the passed in logs to our database, for rapidpro we swallow all errors, logging isn't critical -func (b *backend) WriteChannelLogs(ctx context.Context, logs []*courier.ChannelLog) error { +// WriteChannelLog persists the passed in log to our database, for rapidpro we swallow all errors, logging isn't critical +func (b *backend) WriteChannelLog(ctx context.Context, log *courier.ChannelLogger) error { timeout, cancel := context.WithTimeout(ctx, backendTimeout) defer cancel() - for _, l := range logs { + for _, l := range log.LegacyLogs() { err := writeChannelLog(timeout, b, l) if err != nil { logrus.WithError(err).Error("error writing channel log") diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index a6fae187b..2d8927027 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -961,7 +961,7 @@ func (ts *BackendTestSuite) TestChanneLog() { trace, err := httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) ts.NoError(err) - log := courier.NewChannelLogFromTrace("Message Send Error", knChannel, courier.NilMsgID, trace) + log := courier.NewLegacyChannelLog("Message Send Error", knChannel, courier.NilMsgID, trace) err = writeChannelLog(ctx, ts.b, log) ts.NoError(err) diff --git a/backends/rapidpro/contact.go b/backends/rapidpro/contact.go index 945806577..f6deb703a 100644 --- a/backends/rapidpro/contact.go +++ b/backends/rapidpro/contact.go @@ -140,7 +140,7 @@ func contactForURN(ctx context.Context, b *backend, org OrgID, channel *DBChanne describer, isDescriber := handler.(courier.URNDescriber) if isDescriber { // TODO: this should be created by the server and passed down - logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, channel) + logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) atts, err := describer.DescribeURN(ctx, channel, urn, logger) diff --git a/channel_log.go b/channel_log.go index 0bfd00efa..23b6de8bd 100644 --- a/channel_log.go +++ b/channel_log.go @@ -5,6 +5,7 @@ import ( "strings" "time" + "github.com/nyaruka/gocommon/dates" "github.com/nyaruka/gocommon/httpx" ) @@ -24,8 +25,8 @@ func SanitizeBody(body string) string { return body } -// NewChannelLogFromTrace creates a new channel log for the passed in channel, id, and http trace -func NewChannelLogFromTrace(description string, channel Channel, msgID MsgID, trace *httpx.Trace) *ChannelLog { +// NewLegacyChannelLog creates a new channel log for the passed in channel, id, and http trace +func NewLegacyChannelLog(description string, channel Channel, msgID MsgID, trace *httpx.Trace) *ChannelLog { log := &ChannelLog{ Description: description, Channel: channel, @@ -45,7 +46,7 @@ func NewChannelLogFromTrace(description string, channel Channel, msgID MsgID, tr return log } -func newChannelLogFromError(description string, channel Channel, msgID MsgID, elapsed time.Duration, err error) *ChannelLog { +func newLegacyChannelLogFromError(description string, channel Channel, msgID MsgID, elapsed time.Duration, err error) *ChannelLog { return &ChannelLog{ Description: description, Channel: channel, @@ -113,17 +114,20 @@ type ChannelLogger struct { channel Channel msgID MsgID - traces []*httpx.Trace - errors []string - logs []*ChannelLog + traces []*httpx.Trace + errors []string + createdOn time.Time + + // deprecated + logs []*ChannelLog } -func NewChannelLoggerForSend(msg Msg) *ChannelLogger { - return &ChannelLogger{type_: ChannelLogTypeMsgSend, channel: msg.Channel(), msgID: msg.ID()} +func NewChannelLogForSend(msg Msg) *ChannelLogger { + return &ChannelLogger{type_: ChannelLogTypeMsgSend, channel: msg.Channel(), msgID: msg.ID(), createdOn: dates.Now()} } -func NewChannelLogger(t ChannelLogType, channel Channel) *ChannelLogger { - return &ChannelLogger{type_: t, channel: channel} +func NewChannelLog(t ChannelLogType, channel Channel) *ChannelLogger { + return &ChannelLogger{type_: t, channel: channel, createdOn: dates.Now()} } func (l *ChannelLogger) SetType(t ChannelLogType) { @@ -140,7 +144,7 @@ func (l *ChannelLogger) Recorder(r *httpx.Recorder) { l.traces = append([]*httpx.Trace{r.Trace}, l.traces...) if l.channel != nil { - l.logs = append(l.logs, NewChannelLogFromTrace(logTypeDescriptions[l.type_], l.channel, l.msgID, r.Trace)) + l.logs = append(l.logs, NewLegacyChannelLog(logTypeDescriptions[l.type_], l.channel, l.msgID, r.Trace)) } } @@ -149,7 +153,7 @@ func (l *ChannelLogger) HTTP(t *httpx.Trace) { l.traces = append(l.traces, t) if l.channel != nil { - l.logs = append(l.logs, NewChannelLogFromTrace(logTypeDescriptions[l.type_], l.channel, l.msgID, t)) + l.logs = append(l.logs, NewLegacyChannelLog(logTypeDescriptions[l.type_], l.channel, l.msgID, t)) } } @@ -161,15 +165,27 @@ func (l *ChannelLogger) Error(err error) { if len(l.logs) > 0 && l.logs[len(l.logs)-1].Error == "" { l.logs[len(l.logs)-1].Error = err.Error() } else { - l.logs = append(l.logs, newChannelLogFromError(logTypeDescriptions[l.type_], l.channel, l.msgID, 0, err)) + l.logs = append(l.logs, newLegacyChannelLogFromError(logTypeDescriptions[l.type_], l.channel, l.msgID, 0, err)) } } } +func (l *ChannelLogger) Type() ChannelLogType { + return l.type_ +} + +func (l *ChannelLogger) Traces() []*httpx.Trace { + return l.traces +} + func (l *ChannelLogger) Errors() []string { return l.errors } -func (l *ChannelLogger) Logs() []*ChannelLog { +func (l *ChannelLogger) LegacyLogs() []*ChannelLog { return l.logs } + +func (l *ChannelLogger) CreatedOn() time.Time { + return l.createdOn +} diff --git a/channel_log_test.go b/channel_log_test.go index a3b58fd94..8df4f204d 100644 --- a/channel_log_test.go +++ b/channel_log_test.go @@ -26,7 +26,7 @@ func TestNewChannelLogFromTrace(t *testing.T) { trace, err := httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) assert.NoError(t, err) - log := courier.NewChannelLogFromTrace("Send message", channel, courier.NewMsgID(1234), trace) + log := courier.NewLegacyChannelLog("Send message", channel, courier.NewMsgID(1234), trace) assert.Equal(t, "Send message", log.Description) assert.Equal(t, channel, log.Channel) @@ -45,7 +45,7 @@ func TestNewChannelLogFromTrace(t *testing.T) { trace, err = httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) assert.EqualError(t, err, "unable to connect to server") - log = courier.NewChannelLogFromTrace("Send message", channel, courier.NewMsgID(1234), trace) + log = courier.NewLegacyChannelLog("Send message", channel, courier.NewMsgID(1234), trace) assert.Equal(t, 0, log.StatusCode) assert.Equal(t, "", log.Error) diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index 94b925f3c..3761a8267 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -495,7 +495,7 @@ func TestDescribe(t *testing.T) { channel := testChannels[0] handler := newHandler().(courier.URNDescriber) - logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, channel) + logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) tcs := []struct { urn urns.URN diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index d35c40787..ab151d52c 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -191,7 +191,7 @@ func TestDescribeFBA(t *testing.T) { channel := testChannelsFBA[0] handler := newHandler("FBA", "Facebook", false).(courier.URNDescriber) - logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, channel) + logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) tcs := []struct { urn urns.URN @@ -214,7 +214,7 @@ func TestDescribeIG(t *testing.T) { channel := testChannelsIG[0] handler := newHandler("IG", "Instagram", false).(courier.URNDescriber) - logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, channel) + logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) tcs := []struct { urn urns.URN @@ -233,7 +233,7 @@ func TestDescribeIG(t *testing.T) { func TestDescribeWAC(t *testing.T) { channel := testChannelsWAC[0] handler := newHandler("WAC", "Cloud API WhatsApp", false).(courier.URNDescriber) - logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, channel) + logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) tcs := []struct { urn urns.URN diff --git a/handlers/http_test.go b/handlers/http_test.go index ff5e7ca7a..fd79e9316 100644 --- a/handlers/http_test.go +++ b/handlers/http_test.go @@ -24,16 +24,16 @@ func TestDoHTTPRequest(t *testing.T) { mb := test.NewMockBackend() mc := test.NewMockChannel("7a8ff1d4-f211-4492-9d05-e1905f6da8c8", "NX", "1234", "EC", nil) mm := mb.NewOutgoingMsg(mc, courier.NewMsgID(123), urns.URN("tel:+1234"), "Hello World", false, nil, "", "") - logger := courier.NewChannelLoggerForSend(mm) + logger := courier.NewChannelLogForSend(mm) req, _ := http.NewRequest("POST", "https://api.messages.com/send.json", nil) resp, respBody, err := handlers.RequestHTTP(req, logger) assert.NoError(t, err) assert.Equal(t, 200, resp.StatusCode) assert.Equal(t, []byte(`{"status":"success"}`), respBody) - assert.Len(t, logger.Logs(), 1) + assert.Len(t, logger.LegacyLogs(), 1) - log1 := logger.Logs()[0] + log1 := logger.LegacyLogs()[0] assert.Equal(t, 200, log1.StatusCode) assert.Equal(t, mc, log1.Channel) assert.Equal(t, courier.NewMsgID(123), log1.MsgID) @@ -43,9 +43,9 @@ func TestDoHTTPRequest(t *testing.T) { resp, respBody, err = handlers.RequestHTTP(req, logger) assert.NoError(t, err) assert.Equal(t, 400, resp.StatusCode) - assert.Len(t, logger.Logs(), 2) + assert.Len(t, logger.LegacyLogs(), 2) - log2 := logger.Logs()[1] + log2 := logger.LegacyLogs()[1] assert.Equal(t, 400, log2.StatusCode) assert.Equal(t, mc, log2.Channel) assert.Equal(t, courier.NewMsgID(123), log2.MsgID) diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index a55a69696..6de7c3a20 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -168,7 +168,7 @@ type fetchPayload struct { // fetchAccessToken tries to fetch a new token for our channel, setting the result in redis func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) error { - logger := courier.NewChannelLogger(courier.ChannelLogTypeTokenFetch, channel) + logger := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel) tokenURL, _ := url.Parse(fmt.Sprintf("%s/%s", sendURL, "auth/token.action")) payload := &fetchPayload{ @@ -186,13 +186,13 @@ func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) resp, respBody, err := handlers.RequestHTTP(req, logger) if err != nil || resp.StatusCode/100 != 2 { - return h.Backend().WriteChannelLogs(ctx, logger.Logs()) + return h.Backend().WriteChannelLog(ctx, logger) } accessToken, err := jsonparser.GetString(respBody, "access_token") if err != nil { logger.Error(errors.New("access_token not found in response")) - return h.Backend().WriteChannelLogs(ctx, logger.Logs()) + return h.Backend().WriteChannelLog(ctx, logger) } rc := h.Backend().RedisPool().Get() diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index 5852eb317..70b900bc6 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -272,7 +272,7 @@ func TestDescribeURN(t *testing.T) { s := newServer(mb) handler := &handler{handlers.NewBaseHandler(courier.ChannelType("JC"), "Jiochat")} handler.Initialize(s) - logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, testChannels[0]) + logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) tcs := []struct { urn urns.URN diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index f796de582..0cf81b90c 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -360,7 +360,7 @@ func TestDescribeURN(t *testing.T) { defer server.Close() handler := newHandler().(courier.URNDescriber) - logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, testChannels[0]) + logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) urn, _ := urns.NewURNFromParts(urns.SlackScheme, "U012345", "", "") data := map[string]string{"name": "dummy user"} diff --git a/handlers/test.go b/handlers/test.go index 5be1ba361..5ce7c30ef 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -246,7 +246,7 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour tc.SendPrep(server, handler, channel, msg) } - logger := courier.NewChannelLoggerForSend(msg) + logger := courier.NewChannelLogForSend(msg) ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*10) status, err := handler.Send(ctx, msg, logger) diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index 9929e8ece..5c551d1e4 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -374,7 +374,7 @@ func TestDescribeURN(t *testing.T) { defer server.Close() handler := newHandler().(courier.URNDescriber) - logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, testChannels[0]) + logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) urn, _ := urns.NewURNFromParts(urns.VKScheme, "123456789", "", "") data := map[string]string{"name": "John Doe"} diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index 051e3abbc..97e9daca8 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -97,7 +97,7 @@ func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http // fetchAccessToken tries to fetch a new token for our channel, setting the result in redis func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) error { - logger := courier.NewChannelLogger(courier.ChannelLogTypeTokenFetch, channel) + logger := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel) form := url.Values{ "grant_type": []string{"client_credential"}, @@ -113,13 +113,13 @@ func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) resp, respBody, err := handlers.RequestHTTP(req, logger) if err != nil || resp.StatusCode/100 != 2 { - return h.Backend().WriteChannelLogs(ctx, logger.Logs()) + return h.Backend().WriteChannelLog(ctx, logger) } accessToken, err := jsonparser.GetString(respBody, "access_token") if err != nil { logger.Error(errors.New("access_token not found in response")) - return h.Backend().WriteChannelLogs(ctx, logger.Logs()) + return h.Backend().WriteChannelLog(ctx, logger) } expiration, err := jsonparser.GetInt(respBody, "expires_in") diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index 54bf92e00..02f011db1 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -268,7 +268,7 @@ func TestDescribe(t *testing.T) { s := newServer(mb) handler := &handler{handlers.NewBaseHandler(courier.ChannelType("WC"), "WeChat")} handler.Initialize(s) - logger := courier.NewChannelLogger(courier.ChannelLogTypeUnknown, testChannels[0]) + logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) tcs := []struct { urn urns.URN diff --git a/sender.go b/sender.go index 181590597..06b4af714 100644 --- a/sender.go +++ b/sender.go @@ -189,7 +189,7 @@ func (w *Sender) sendMessage(msg Msg) { } var status MsgStatus - logger := NewChannelLoggerForSend(msg) + logger := NewChannelLogForSend(msg) if sent { // if this message was already sent, create a wired status for it @@ -231,7 +231,7 @@ func (w *Sender) sendMessage(msg Msg) { } // write our logs as well - err = backend.WriteChannelLogs(writeCTX, logger.Logs()) + err = backend.WriteChannelLog(writeCTX, logger) if err != nil { log.WithError(err).Info("error writing msg logs") } diff --git a/server.go b/server.go index 478c1a796..fe0b4bffd 100644 --- a/server.go +++ b/server.go @@ -298,7 +298,7 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe } }() - logger := NewChannelLogger(ChannelLogTypeUnknown, channel) + logger := NewChannelLog(ChannelLogTypeUnknown, channel) events, hErr := handlerFunc(ctx, channel, recorder.ResponseWriter, r, logger) duration := time.Since(start) @@ -347,7 +347,7 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe } } - if err := s.backend.WriteChannelLogs(ctx, logger.Logs()); err != nil { + if err := s.backend.WriteChannelLog(ctx, logger); err != nil { logrus.WithError(err).Error("error writing channel log") } } diff --git a/test/backend.go b/test/backend.go index dd4b22290..fb444f06d 100644 --- a/test/backend.go +++ b/test/backend.go @@ -34,7 +34,7 @@ type MockBackend struct { outgoingMsgs []courier.Msg msgStatuses []courier.MsgStatus channelEvents []courier.ChannelEvent - channelLogs []*courier.ChannelLog + channelLogs []*courier.ChannelLogger lastContactName string sentMsgs map[courier.MsgID]bool seenExternalIDs []string @@ -74,9 +74,9 @@ func NewMockBackend() *MockBackend { } } -func (mb *MockBackend) ChannelLogs() []*courier.ChannelLog { return mb.channelLogs } -func (mb *MockBackend) MsgStatuses() []courier.MsgStatus { return mb.msgStatuses } -func (mb *MockBackend) ClearMsgStatuses() { mb.msgStatuses = nil } +func (mb *MockBackend) ChannelLogs() []*courier.ChannelLogger { return mb.channelLogs } +func (mb *MockBackend) MsgStatuses() []courier.MsgStatus { return mb.msgStatuses } +func (mb *MockBackend) ClearMsgStatuses() { mb.msgStatuses = nil } // GetLastQueueMsg returns the last message queued to the server func (mb *MockBackend) GetLastQueueMsg() (courier.Msg, error) { @@ -95,7 +95,7 @@ func (mb *MockBackend) GetLastChannelEvent() (courier.ChannelEvent, error) { } // GetLastChannelLog returns the last channel log written to the server -func (mb *MockBackend) GetLastChannelLog() (*courier.ChannelLog, error) { +func (mb *MockBackend) GetLastChannelLog() (*courier.ChannelLogger, error) { if len(mb.channelLogs) == 0 { return nil, errors.New("no channel logs") } @@ -181,14 +181,12 @@ func (mb *MockBackend) MarkOutgoingMsgComplete(ctx context.Context, msg courier. mb.sentMsgs[msg.ID()] = true } -// WriteChannelLogs writes the passed in channel logs to the DB -func (mb *MockBackend) WriteChannelLogs(ctx context.Context, logs []*courier.ChannelLog) error { +// WriteChannelLog writes the passed in channel log to the DB +func (mb *MockBackend) WriteChannelLog(ctx context.Context, log *courier.ChannelLogger) error { mb.mutex.Lock() defer mb.mutex.Unlock() - for _, log := range logs { - mb.channelLogs = append(mb.channelLogs, log) - } + mb.channelLogs = append(mb.channelLogs, log) return nil } From 03e6d3e9b213414722bcfa2d3bdd75ff15a4221f Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 23 Aug 2022 15:07:29 -0500 Subject: [PATCH 092/294] Rename logger *ChannelLogger variables to avoid confusion with logrus --- backends/rapidpro/contact.go | 4 +-- handler_test.go | 4 +-- handlers/africastalking/africastalking.go | 8 ++--- handlers/arabiacell/arabiacell.go | 16 +++++---- handlers/blackmyna/blackmyna.go | 8 ++--- handlers/bongolive/bongolive.go | 6 ++-- handlers/burstsms/burstsms.go | 18 +++++----- handlers/chikka/chikka.go | 8 ++--- handlers/clickatell/clickatell.go | 10 +++--- handlers/clickmobile/clickmobile.go | 8 ++--- handlers/clicksend/clicksend.go | 36 ++++++++++---------- handlers/dart/dart.go | 10 +++--- handlers/discord/discord.go | 12 +++---- handlers/dmark/dmark.go | 10 +++--- handlers/external/external.go | 16 ++++----- handlers/facebook/facebook.go | 28 ++++++++-------- handlers/facebookapp/facebookapp.go | 40 +++++++++++------------ handlers/firebase/firebase.go | 12 +++---- handlers/freshchat/freshchat.go | 8 ++--- handlers/generic.go | 4 +-- handlers/globe/globe.go | 6 ++-- handlers/highconnection/highconnection.go | 8 ++--- handlers/hormuud/hormuud.go | 8 ++--- handlers/http.go | 12 +++---- handlers/http_test.go | 14 ++++---- handlers/telesom/telesom.go | 8 ++--- handlers/test.go | 8 ++--- handlers/yo/yo.go | 6 ++-- handlers/zenvia/zenvia.go | 10 +++--- handlers/zenviaold/zenviaold.go | 10 +++--- sender.go | 8 ++--- server.go | 4 +-- 32 files changed, 185 insertions(+), 183 deletions(-) diff --git a/backends/rapidpro/contact.go b/backends/rapidpro/contact.go index f6deb703a..2c17dd58e 100644 --- a/backends/rapidpro/contact.go +++ b/backends/rapidpro/contact.go @@ -140,9 +140,9 @@ func contactForURN(ctx context.Context, b *backend, org OrgID, channel *DBChanne describer, isDescriber := handler.(courier.URNDescriber) if isDescriber { // TODO: this should be created by the server and passed down - logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) - atts, err := describer.DescribeURN(ctx, channel, urn, logger) + atts, err := describer.DescribeURN(ctx, channel, urn, clog) // in the case of errors, we log the error but move onwards anyways if err != nil { diff --git a/handler_test.go b/handler_test.go index 5fb833c7a..650a62357 100644 --- a/handler_test.go +++ b/handler_test.go @@ -46,12 +46,12 @@ func (h *dummyHandler) Initialize(s courier.Server) error { } // Send sends the given message, logging any HTTP calls or errors -func (h *dummyHandler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *dummyHandler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { return h.backend.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgSent), nil } // ReceiveMsg sends the passed in message, returning any error -func (h *dummyHandler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *dummyHandler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { r.ParseForm() from := r.Form.Get("from") text := r.Form.Get("text") diff --git a/handlers/africastalking/africastalking.go b/handlers/africastalking/africastalking.go index 7db6ce1ae..35ac50ac6 100644 --- a/handlers/africastalking/africastalking.go +++ b/handlers/africastalking/africastalking.go @@ -48,7 +48,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -94,7 +94,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -114,7 +114,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { isSharedStr := msg.Channel().ConfigForKey(configIsShared, false) isShared, _ := isSharedStr.(bool) @@ -150,7 +150,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.Header.Set("apikey", apiKey) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/arabiacell/arabiacell.go b/handlers/arabiacell/arabiacell.go index 6e627d897..1c949086f 100644 --- a/handlers/arabiacell/arabiacell.go +++ b/handlers/arabiacell/arabiacell.go @@ -43,9 +43,11 @@ func (h *handler) Initialize(s courier.Server) error { } // -// XXX -// response_text -// message_id_in_case_of_success_sending +// +// XXX +// response_text +// message_id_in_case_of_success_sending +// // type mtResponse struct { Code string `xml:"code"` @@ -54,7 +56,7 @@ type mtResponse struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for AC channel") @@ -94,7 +96,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/xml") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -103,7 +105,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha response := &mtResponse{} err = xml.Unmarshal(respBody, response) if err != nil { - logger.Error(err) + clog.Error(err) break } @@ -113,7 +115,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha status.SetExternalID(response.MessageID) } else { status.SetStatus(courier.MsgFailed) - logger.Error(fmt.Errorf("Received invalid response code: %s", response.Code)) + clog.Error(fmt.Errorf("Received invalid response code: %s", response.Code)) break } } diff --git a/handlers/blackmyna/blackmyna.go b/handlers/blackmyna/blackmyna.go index c95bf97c9..ad1bd60a4 100644 --- a/handlers/blackmyna/blackmyna.go +++ b/handlers/blackmyna/blackmyna.go @@ -42,7 +42,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -76,7 +76,7 @@ var statusMapping = map[int]courier.MsgStatusValue{ } // StatusMessage is our HTTP handler function for status updates -func (h *handler) StatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) StatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -95,7 +95,7 @@ func (h *handler) StatusMessage(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for BM channel") @@ -128,7 +128,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.SetBasicAuth(username, password) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/bongolive/bongolive.go b/handlers/bongolive/bongolive.go index 4e85819cb..f4c9374e1 100644 --- a/handlers/bongolive/bongolive.go +++ b/handlers/bongolive/bongolive.go @@ -64,7 +64,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { var err error form := &moForm{} err = handlers.DecodeAndValidateForm(form, r) @@ -124,7 +124,7 @@ func writeBongoLiveResponse(w http.ResponseWriter) error { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for %s channel", msg.Channel().ChannelType()) @@ -163,7 +163,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - resp, respBody, err := handlers.RequestHTTPInsecure(req, logger) + resp, respBody, err := handlers.RequestHTTPInsecure(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/burstsms/burstsms.go b/handlers/burstsms/burstsms.go index 6366a97f0..68103d58d 100644 --- a/handlers/burstsms/burstsms.go +++ b/handlers/burstsms/burstsms.go @@ -46,17 +46,17 @@ func (h *handler) Initialize(s courier.Server) error { return nil } -// { -// message_id: 19835, -// recipients: 3, -// cost: 1.000 -// } +// { +// message_id: 19835, +// recipients: 3, +// cost: 1.000 +// } type mtResponse struct { MessageID int64 `json:"message_id"` } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for BS channel") @@ -83,7 +83,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -92,7 +92,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha response := &mtResponse{} err = json.Unmarshal(respBody, response) if err != nil { - logger.Error(err) + clog.Error(err) break } @@ -101,7 +101,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha status.SetExternalID(fmt.Sprintf("%d", response.MessageID)) } else { status.SetStatus(courier.MsgFailed) - logger.Error(fmt.Errorf("Received invalid message id: %d", response.MessageID)) + clog.Error(fmt.Errorf("Received invalid message id: %d", response.MessageID)) break } } diff --git a/handlers/chikka/chikka.go b/handlers/chikka/chikka.go index 261fac305..7485e7472 100644 --- a/handlers/chikka/chikka.go +++ b/handlers/chikka/chikka.go @@ -56,7 +56,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) @@ -104,7 +104,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for CK channel") @@ -140,7 +140,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if resp != nil && resp.StatusCode == 400 { message, _ := jsonparser.GetString(respBody, "message") @@ -153,7 +153,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req, _ = http.NewRequest(http.MethodPost, sendURL, strings.NewReader(form.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - resp, _, err = handlers.RequestHTTP(req, logger) + resp, _, err = handlers.RequestHTTP(req, clog) } } diff --git a/handlers/clickatell/clickatell.go b/handlers/clickatell/clickatell.go index 2de80cc3f..4f88c3421 100644 --- a/handlers/clickatell/clickatell.go +++ b/handlers/clickatell/clickatell.go @@ -65,7 +65,7 @@ var statusMapping = map[int]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &statusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) @@ -99,7 +99,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) @@ -169,7 +169,7 @@ func decodeUTF16BE(b []byte) (string, error) { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { apiKey := msg.Channel().StringConfigForKey(courier.ConfigAPIKey, "") if apiKey == "" { return nil, fmt.Errorf("no api_key set for CT channel") @@ -195,7 +195,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -203,7 +203,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha // try to read out our message id, if we can't then this was a failure externalID, err := jsonparser.GetString(respBody, "messages", "[0]", "apiMessageId") if err != nil { - logger.Error(err) + clog.Error(err) } else { status.SetStatus(courier.MsgWired) status.SetExternalID(externalID) diff --git a/handlers/clickmobile/clickmobile.go b/handlers/clickmobile/clickmobile.go index cca1a1421..b5ab632a5 100644 --- a/handlers/clickmobile/clickmobile.go +++ b/handlers/clickmobile/clickmobile.go @@ -59,7 +59,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateXML(payload, r) if err != nil { @@ -98,7 +98,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for CM channel") @@ -156,7 +156,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -165,7 +165,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha if responseCode == "000" { status.SetStatus(courier.MsgWired) } else { - logger.Error(fmt.Errorf("Received invalid response content: %s", string(respBody))) + clog.Error(fmt.Errorf("Received invalid response content: %s", string(respBody))) } } return status, nil diff --git a/handlers/clicksend/clicksend.go b/handlers/clicksend/clicksend.go index f49391a9e..3248d15a3 100644 --- a/handlers/clicksend/clicksend.go +++ b/handlers/clicksend/clicksend.go @@ -37,20 +37,20 @@ func (h *handler) Initialize(s courier.Server) error { return nil } -// { -// "messages": [ -// { -// "to": "+61411111111", -// "source": "sdk", -// "body": "body" -// }, -// { -// "list_id": 0, -// "source": "sdk", -// "body": "body" -// } -// ] -// } +// { +// "messages": [ +// { +// "to": "+61411111111", +// "source": "sdk", +// "body": "body" +// }, +// { +// "list_id": 0, +// "source": "sdk", +// "body": "body" +// } +// ] +// } type mtPayload struct { Messages [1]struct { To string `json:"to"` @@ -61,7 +61,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("Missing 'username' config for CS channel") @@ -93,7 +93,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.SetBasicAuth(username, password) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -101,14 +101,14 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha // first read our status s, err := jsonparser.GetString(respBody, "data", "messages", "[0]", "status") if s != "SUCCESS" { - logger.Error(errors.Errorf("received non SUCCESS status: %s", s)) + clog.Error(errors.Errorf("received non SUCCESS status: %s", s)) return status, nil } // then get our external id id, err := jsonparser.GetString(respBody, "data", "messages", "[0]", "message_id") if err != nil { - logger.Error(errors.Errorf("unable to get message_id for message")) + clog.Error(errors.Errorf("unable to get message_id for message")) return status, nil } diff --git a/handlers/dart/dart.go b/handlers/dart/dart.go index 5efca19b8..8c723a912 100644 --- a/handlers/dart/dart.go +++ b/handlers/dart/dart.go @@ -56,7 +56,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -89,7 +89,7 @@ type statusForm struct { } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -139,7 +139,7 @@ func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWr } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for %s channel", msg.Channel().ChannelType()) @@ -179,7 +179,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -193,7 +193,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha if responseText == "101" { errorMessage = "Error 101: Account expired or invalid parameters" } - logger.Error(fmt.Errorf(errorMessage)) + clog.Error(fmt.Errorf(errorMessage)) return status, nil } diff --git a/handlers/discord/discord.go b/handlers/discord/discord.go index 353895a60..bf613c9ab 100644 --- a/handlers/discord/discord.go +++ b/handlers/discord/discord.go @@ -69,7 +69,7 @@ func getFormField(form url.Values, name string) string { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { var err error var from, text string @@ -119,8 +119,8 @@ func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWr // buildStatusHandler deals with building a handler that takes what status is received in the URL func (h *handler) buildStatusHandler(status string) courier.ChannelHandleFunc { - return func(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { - return h.receiveStatus(ctx, status, channel, w, r, logger) + return func(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { + return h.receiveStatus(ctx, status, channel, w, r, clog) } } @@ -135,7 +135,7 @@ var statusMappings = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, statusString string, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, statusString string, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -154,7 +154,7 @@ func (h *handler) receiveStatus(ctx context.Context, statusString string, channe } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { sendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, "") if sendURL == "" { return nil, fmt.Errorf("no send url set for DS channel") @@ -208,7 +208,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Authorization", authorization) } - resp, _, err := handlers.RequestHTTP(req, logger) + resp, _, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/dmark/dmark.go b/handlers/dmark/dmark.go index 620082d2e..4ec72773e 100644 --- a/handlers/dmark/dmark.go +++ b/handlers/dmark/dmark.go @@ -47,7 +47,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -88,7 +88,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -107,7 +107,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { // get our authentication token auth := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if auth == "" { @@ -135,7 +135,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Token %s", auth)) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -143,7 +143,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha // grab the external id externalID, err := jsonparser.GetString(respBody, "sms_id") if err != nil { - logger.Error(errors.Errorf("unable to get sms_id from body")) + clog.Error(errors.Errorf("unable to get sms_id from body")) return status, nil } diff --git a/handlers/external/external.go b/handlers/external/external.go index a012d2a42..da55bc584 100644 --- a/handlers/external/external.go +++ b/handlers/external/external.go @@ -93,7 +93,7 @@ type stopContactForm struct { From string `validate:"required" name:"from"` } -func (h *handler) receiveStopContact(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStopContact(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &stopContactForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -142,7 +142,7 @@ func getFormField(form url.Values, defaultNames []string, name string) string { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { var err error var from, dateString, text string @@ -238,8 +238,8 @@ func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWr // buildStatusHandler deals with building a handler that takes what status is received in the URL func (h *handler) buildStatusHandler(status string) courier.ChannelHandleFunc { - return func(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { - return h.receiveStatus(ctx, status, channel, w, r, logger) + return func(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { + return h.receiveStatus(ctx, status, channel, w, r, clog) } } @@ -254,7 +254,7 @@ var statusMappings = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, statusString string, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, statusString string, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -273,7 +273,7 @@ func (h *handler) receiveStatus(ctx context.Context, statusString string, channe } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { sendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, "") if sendURL == "" { return nil, fmt.Errorf("no send url set for EX channel") @@ -363,7 +363,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set(hKey, fmt.Sprint(hValue)) } - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -371,7 +371,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha if responseContent == "" || strings.Contains(string(respBody), responseContent) { status.SetStatus(courier.MsgWired) } else { - logger.Error(fmt.Errorf("Received invalid response content: %s", string(respBody))) + clog.Error(fmt.Errorf("Received invalid response content: %s", string(respBody))) } } diff --git a/handlers/facebook/facebook.go b/handlers/facebook/facebook.go index 4771c5e22..12522ca31 100644 --- a/handlers/facebook/facebook.go +++ b/handlers/facebook/facebook.go @@ -77,7 +77,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveVerify handles Facebook's webhook verification callback -func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { mode := r.URL.Query().Get("hub.mode") // this isn't a subscribe verification, that's an error @@ -206,7 +206,7 @@ type moPayload struct { } // receiveEvent is our HTTP handler function for incoming messages and status updates -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -473,7 +473,7 @@ type mtQuickReply struct { ContentType string `json:"content_type"` } -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { // can't do anything without an access token accessToken := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if accessToken == "" { @@ -555,14 +555,14 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } externalID, err := jsonparser.GetString(respBody, "message_id") if err != nil { - logger.Error(errors.Errorf("unable to get message_id from body")) + clog.Error(errors.Errorf("unable to get message_id from body")) return status, nil } @@ -572,7 +572,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha if msg.URN().IsFacebookRef() { recipientID, err := jsonparser.GetString(respBody, "recipient_id") if err != nil { - logger.Error(errors.Errorf("unable to get recipient_id from body")) + clog.Error(errors.Errorf("unable to get recipient_id from body")) return status, nil } @@ -580,29 +580,29 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha realIDURN, err := urns.NewFacebookURN(recipientID) if err != nil { - logger.Error(errors.Errorf("unable to make facebook urn from %s", recipientID)) + clog.Error(errors.Errorf("unable to make facebook urn from %s", recipientID)) } contact, err := h.Backend().GetContact(ctx, msg.Channel(), msg.URN(), "", "") if err != nil { - logger.Error(errors.Errorf("unable to get contact for %s", msg.URN().String())) + clog.Error(errors.Errorf("unable to get contact for %s", msg.URN().String())) } realURN, err := h.Backend().AddURNtoContact(ctx, msg.Channel(), contact, realIDURN) if err != nil { - logger.Error(errors.Errorf("unable to add real facebook URN %s to contact with uuid %s", realURN.String(), contact.UUID())) + clog.Error(errors.Errorf("unable to add real facebook URN %s to contact with uuid %s", realURN.String(), contact.UUID())) } referralIDExtURN, err := urns.NewURNFromParts(urns.ExternalScheme, referralID, "", "") if err != nil { - logger.Error(errors.Errorf("unable to make ext urn from %s", referralID)) + clog.Error(errors.Errorf("unable to make ext urn from %s", referralID)) } extURN, err := h.Backend().AddURNtoContact(ctx, msg.Channel(), contact, referralIDExtURN) if err != nil { - logger.Error(errors.Errorf("unable to add URN %s to contact with uuid %s", extURN.String(), contact.UUID())) + clog.Error(errors.Errorf("unable to add URN %s to contact with uuid %s", extURN.String(), contact.UUID())) } referralFacebookURN, err := h.Backend().RemoveURNfromContact(ctx, msg.Channel(), contact, msg.URN()) if err != nil { - logger.Error(errors.Errorf("unable to remove referral facebook URN %s from contact with uuid %s", referralFacebookURN.String(), contact.UUID())) + clog.Error(errors.Errorf("unable to remove referral facebook URN %s from contact with uuid %s", referralFacebookURN.String(), contact.UUID())) } } } @@ -615,7 +615,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } // DescribeURN looks up URN metadata for new contacts -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, logger *courier.ChannelLogger) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLogger) (map[string]string, error) { // can't do anything with facebook refs, ignore them if urn.IsFacebookRef() { return map[string]string{}, nil @@ -637,7 +637,7 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn u.RawQuery = query.Encode() req, _ := http.NewRequest(http.MethodGet, u.String(), nil) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("unable to look up contact data") } diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 0b587628f..24b16f8bc 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -312,7 +312,7 @@ func (h *handler) GetChannel(ctx context.Context, r *http.Request) (courier.Chan } // receiveVerify handles Facebook's webhook verification callback -func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { mode := r.URL.Query().Get("hub.mode") // this isn't a subscribe verification, that's an error @@ -354,7 +354,7 @@ func resolveMediaURL(mediaID string, token string) (string, error) { } // receiveEvent is our HTTP handler function for incoming messages and status updates -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { err := h.validateSignature(r) if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) @@ -803,17 +803,17 @@ type mtQuickReply struct { ContentType string `json:"content_type"` } -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { if msg.Channel().ChannelType() == "FBA" || msg.Channel().ChannelType() == "IG" { - return h.sendFacebookInstagramMsg(ctx, msg, logger) + return h.sendFacebookInstagramMsg(ctx, msg, clog) } else if msg.Channel().ChannelType() == "WAC" { - return h.sendCloudAPIWhatsappMsg(ctx, msg, logger) + return h.sendCloudAPIWhatsappMsg(ctx, msg, clog) } return nil, fmt.Errorf("unssuported channel type") } -func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { // can't do anything without an access token accessToken := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if accessToken == "" { @@ -894,14 +894,14 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } externalID, err := jsonparser.GetString(respBody, "message_id") if err != nil { - logger.Error(errors.Errorf("unable to get message_id from body")) + clog.Error(errors.Errorf("unable to get message_id from body")) return status, nil } @@ -911,7 +911,7 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, if msg.URN().IsFacebookRef() { recipientID, err := jsonparser.GetString(respBody, "recipient_id") if err != nil { - logger.Error(errors.Errorf("unable to get recipient_id from body")) + clog.Error(errors.Errorf("unable to get recipient_id from body")) return status, nil } @@ -919,29 +919,29 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, realIDURN, err := urns.NewFacebookURN(recipientID) if err != nil { - logger.Error(errors.Errorf("unable to make facebook urn from %s", recipientID)) + clog.Error(errors.Errorf("unable to make facebook urn from %s", recipientID)) } contact, err := h.Backend().GetContact(ctx, msg.Channel(), msg.URN(), "", "") if err != nil { - logger.Error(errors.Errorf("unable to get contact for %s", msg.URN().String())) + clog.Error(errors.Errorf("unable to get contact for %s", msg.URN().String())) } realURN, err := h.Backend().AddURNtoContact(ctx, msg.Channel(), contact, realIDURN) if err != nil { - logger.Error(errors.Errorf("unable to add real facebook URN %s to contact with uuid %s", realURN.String(), contact.UUID())) + clog.Error(errors.Errorf("unable to add real facebook URN %s to contact with uuid %s", realURN.String(), contact.UUID())) } referralIDExtURN, err := urns.NewURNFromParts(urns.ExternalScheme, referralID, "", "") if err != nil { - logger.Error(errors.Errorf("unable to make ext urn from %s", referralID)) + clog.Error(errors.Errorf("unable to make ext urn from %s", referralID)) } extURN, err := h.Backend().AddURNtoContact(ctx, msg.Channel(), contact, referralIDExtURN) if err != nil { - logger.Error(errors.Errorf("unable to add URN %s to contact with uuid %s", extURN.String(), contact.UUID())) + clog.Error(errors.Errorf("unable to add URN %s to contact with uuid %s", extURN.String(), contact.UUID())) } referralFacebookURN, err := h.Backend().RemoveURNfromContact(ctx, msg.Channel(), contact, msg.URN()) if err != nil { - logger.Error(errors.Errorf("unable to remove referral facebook URN %s from contact with uuid %s", referralFacebookURN.String(), contact.UUID())) + clog.Error(errors.Errorf("unable to remove referral facebook URN %s from contact with uuid %s", referralFacebookURN.String(), contact.UUID())) } } @@ -1055,7 +1055,7 @@ type wacMTResponse struct { } `json:"messages"` } -func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { // can't do anything without an access token accessToken := h.Server().Config().WhatsappAdminSystemUserToken @@ -1274,7 +1274,7 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -1282,7 +1282,7 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, respPayload := &wacMTResponse{} err = json.Unmarshal(respBody, respPayload) if err != nil { - logger.Error(errors.Errorf("unable to unmarshal response body")) + clog.Error(errors.Errorf("unable to unmarshal response body")) return status, nil } externalID := respPayload.Messages[0].ID @@ -1297,7 +1297,7 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, } // DescribeURN looks up URN metadata for new contacts -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, logger *courier.ChannelLogger) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLogger) (map[string]string, error) { if channel.ChannelType() == "WAC" { return map[string]string{}, nil } @@ -1327,7 +1327,7 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn u.RawQuery = query.Encode() req, _ := http.NewRequest(http.MethodGet, u.String(), nil) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("unable to look up contact data") } diff --git a/handlers/firebase/firebase.go b/handlers/firebase/firebase.go index 7226676b4..bcee98dff 100644 --- a/handlers/firebase/firebase.go +++ b/handlers/firebase/firebase.go @@ -54,7 +54,7 @@ type receiveForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &receiveForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -89,7 +89,7 @@ type registerForm struct { } // registerContact is our HTTP handler function for when a contact is registered (or renewed) -func (h *handler) registerContact(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) registerContact(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := ®isterForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -135,7 +135,7 @@ type mtNotification struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { title := msg.Channel().StringConfigForKey(configTitle, "") if title == "" { return nil, fmt.Errorf("no FCM_TITLE set for FCM channel") @@ -194,7 +194,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("key=%s", fcmKey)) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -202,7 +202,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha // was this successful success, _ := jsonparser.GetInt(respBody, "success") if success != 1 { - logger.Error(errors.Errorf("received non-1 value for success in response")) + clog.Error(errors.Errorf("received non-1 value for success in response")) return status, nil } @@ -210,7 +210,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha if i == 0 { externalID, err := jsonparser.GetInt(respBody, "multicast_id") if err != nil { - logger.Error(errors.Errorf("unable to get multicast_id from response")) + clog.Error(errors.Errorf("unable to get multicast_id from response")) return status, nil } status.SetExternalID(fmt.Sprintf("%d", externalID)) diff --git a/handlers/freshchat/freshchat.go b/handlers/freshchat/freshchat.go index fee86ec00..e92857e19 100644 --- a/handlers/freshchat/freshchat.go +++ b/handlers/freshchat/freshchat.go @@ -48,7 +48,7 @@ func (h *handler) Initialize(s courier.Server) error { s.AddHandlerRoute(h, http.MethodPost, "receive", h.receiveMessage) return nil } -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { err := h.validateSignature(channel, r) if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) @@ -101,7 +101,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) } -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { agentID := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if agentID == "" { @@ -148,7 +148,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha msgimage.Image = &Image{URL: mediaURL} payload.Messages[0].MessageParts = append(payload.Messages[0].MessageParts, *msgimage) default: - logger.Error(fmt.Errorf("unknown media type: %s", mediaType)) + clog.Error(fmt.Errorf("unknown media type: %s", mediaType)) } } @@ -167,7 +167,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha var bearer = "Bearer " + authToken req.Header.Set("Authorization", bearer) - resp, _, err := handlers.RequestHTTP(req, logger) + resp, _, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/generic.go b/handlers/generic.go index 0e7180da9..0fd991e01 100644 --- a/handlers/generic.go +++ b/handlers/generic.go @@ -11,7 +11,7 @@ import ( // NewTelReceiveHandler creates a new receive handler given the passed in text and from fields func NewTelReceiveHandler(h *BaseHandler, fromField string, bodyField string) courier.ChannelHandleFunc { - return func(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { + return func(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, WriteAndLogRequestError(ctx, h, c, w, r, err) @@ -35,7 +35,7 @@ func NewTelReceiveHandler(h *BaseHandler, fromField string, bodyField string) co // NewExternalIDStatusHandler creates a new status handler given the passed in status map and fields func NewExternalIDStatusHandler(h *BaseHandler, statuses map[string]courier.MsgStatusValue, externalIDField string, statusField string) courier.ChannelHandleFunc { - return func(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { + return func(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, WriteAndLogRequestError(ctx, h, c, w, r, err) diff --git a/handlers/globe/globe.go b/handlers/globe/globe.go index 458da045c..cec69dab7 100644 --- a/handlers/globe/globe.go +++ b/handlers/globe/globe.go @@ -73,7 +73,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -126,7 +126,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { appID := msg.Channel().StringConfigForKey(configAppID, "") if appID == "" { return nil, fmt.Errorf("Missing 'app_id' config for GL channel") @@ -163,7 +163,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, _, err := handlers.RequestHTTP(req, logger) + resp, _, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/highconnection/highconnection.go b/handlers/highconnection/highconnection.go index 4191eb28b..61d1b6be9 100644 --- a/handlers/highconnection/highconnection.go +++ b/handlers/highconnection/highconnection.go @@ -46,7 +46,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -98,7 +98,7 @@ var statusMapping = map[int]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -116,7 +116,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for HX channel") @@ -155,7 +155,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return nil, err } - resp, _, err := handlers.RequestHTTP(req, logger) + resp, _, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/hormuud/hormuud.go b/handlers/hormuud/hormuud.go index b8cb0b432..afcdc3d23 100644 --- a/handlers/hormuud/hormuud.go +++ b/handlers/hormuud/hormuud.go @@ -51,7 +51,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateForm(payload, r) if err != nil { @@ -80,10 +80,10 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - token, err := h.FetchToken(ctx, msg.Channel(), msg, logger) + token, err := h.FetchToken(ctx, msg.Channel(), msg, clog) if err != nil { return status, errors.Wrapf(err, "unable to fetch token") } @@ -111,7 +111,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/http.go b/handlers/http.go index 9570e132e..479293d5f 100644 --- a/handlers/http.go +++ b/handlers/http.go @@ -10,24 +10,24 @@ import ( ) // RequestHTTP does the given request, logging the trace, and returns the response -func RequestHTTP(req *http.Request, logger *courier.ChannelLogger) (*http.Response, []byte, error) { - return RequestHTTPWithClient(utils.GetHTTPClient(), req, logger) +func RequestHTTP(req *http.Request, clog *courier.ChannelLogger) (*http.Response, []byte, error) { + return RequestHTTPWithClient(utils.GetHTTPClient(), req, clog) } // RequestHTTPInsecure does the given request using an insecure client that does not validate SSL certificates, // logging the trace, and returns the response -func RequestHTTPInsecure(req *http.Request, logger *courier.ChannelLogger) (*http.Response, []byte, error) { - return RequestHTTPWithClient(utils.GetInsecureHTTPClient(), req, logger) +func RequestHTTPInsecure(req *http.Request, clog *courier.ChannelLogger) (*http.Response, []byte, error) { + return RequestHTTPWithClient(utils.GetInsecureHTTPClient(), req, clog) } // RequestHTTP does the given request using the given client, logging the trace, and returns the response -func RequestHTTPWithClient(client *http.Client, req *http.Request, logger *courier.ChannelLogger) (*http.Response, []byte, error) { +func RequestHTTPWithClient(client *http.Client, req *http.Request, clog *courier.ChannelLogger) (*http.Response, []byte, error) { var resp *http.Response var body []byte trace, err := httpx.DoTrace(client, req, nil, nil, 0) if trace != nil { - logger.HTTP(trace) + clog.HTTP(trace) resp = trace.Response body = trace.ResponseBody } diff --git a/handlers/http_test.go b/handlers/http_test.go index fd79e9316..85e2702af 100644 --- a/handlers/http_test.go +++ b/handlers/http_test.go @@ -24,28 +24,28 @@ func TestDoHTTPRequest(t *testing.T) { mb := test.NewMockBackend() mc := test.NewMockChannel("7a8ff1d4-f211-4492-9d05-e1905f6da8c8", "NX", "1234", "EC", nil) mm := mb.NewOutgoingMsg(mc, courier.NewMsgID(123), urns.URN("tel:+1234"), "Hello World", false, nil, "", "") - logger := courier.NewChannelLogForSend(mm) + clog := courier.NewChannelLogForSend(mm) req, _ := http.NewRequest("POST", "https://api.messages.com/send.json", nil) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) assert.NoError(t, err) assert.Equal(t, 200, resp.StatusCode) assert.Equal(t, []byte(`{"status":"success"}`), respBody) - assert.Len(t, logger.LegacyLogs(), 1) + assert.Len(t, clog.LegacyLogs(), 1) - log1 := logger.LegacyLogs()[0] + log1 := clog.LegacyLogs()[0] assert.Equal(t, 200, log1.StatusCode) assert.Equal(t, mc, log1.Channel) assert.Equal(t, courier.NewMsgID(123), log1.MsgID) assert.Equal(t, "https://api.messages.com/send.json", log1.URL) req, _ = http.NewRequest("POST", "https://api.messages.com/send.json", nil) - resp, respBody, err = handlers.RequestHTTP(req, logger) + resp, _, err = handlers.RequestHTTP(req, clog) assert.NoError(t, err) assert.Equal(t, 400, resp.StatusCode) - assert.Len(t, logger.LegacyLogs(), 2) + assert.Len(t, clog.LegacyLogs(), 2) - log2 := logger.LegacyLogs()[1] + log2 := clog.LegacyLogs()[1] assert.Equal(t, 400, log2.StatusCode) assert.Equal(t, mc, log2.Channel) assert.Equal(t, courier.NewMsgID(123), log2.MsgID) diff --git a/handlers/telesom/telesom.go b/handlers/telesom/telesom.go index 5fad540ff..7d3efbd7f 100644 --- a/handlers/telesom/telesom.go +++ b/handlers/telesom/telesom.go @@ -44,7 +44,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -65,7 +65,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for TS channel") @@ -114,7 +114,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -122,7 +122,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha if strings.Contains(string(respBody), "Success") { status.SetStatus(courier.MsgWired) } else { - logger.Error(fmt.Errorf("Received invalid response content: %s", string(respBody))) + clog.Error(fmt.Errorf("Received invalid response content: %s", string(respBody))) } } return status, nil diff --git a/handlers/test.go b/handlers/test.go index 5ce7c30ef..b7c4988c1 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -246,18 +246,18 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour tc.SendPrep(server, handler, channel, msg) } - logger := courier.NewChannelLogForSend(msg) + clog := courier.NewChannelLogForSend(msg) ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*10) - status, err := handler.Send(ctx, msg, logger) + status, err := handler.Send(ctx, msg, clog) cancel() // we don't currently distinguish between a returned error and logged errors if err != nil { - logger.Error(err) + clog.Error(err) } - assert.Equal(t, tc.ExpectedErrors, logger.Errors(), "unexpected errors logged") + assert.Equal(t, tc.ExpectedErrors, clog.Errors(), "unexpected errors logged") if tc.ExpectedRequestPath != "" { require.NotNil(testRequest, "path should not be nil") diff --git a/handlers/yo/yo.go b/handlers/yo/yo.go index eb8ed4f9d..dcca3339f 100644 --- a/handlers/yo/yo.go +++ b/handlers/yo/yo.go @@ -53,7 +53,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -97,7 +97,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for YO channel") @@ -130,7 +130,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/zenvia/zenvia.go b/handlers/zenvia/zenvia.go index 4b2c5ded8..42fe4f95e 100644 --- a/handlers/zenvia/zenvia.go +++ b/handlers/zenvia/zenvia.go @@ -76,7 +76,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // get our params payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) @@ -156,7 +156,7 @@ type statusPayload struct { } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // get our params payload := &statusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) @@ -194,7 +194,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { channel := msg.Channel() token := channel.StringConfigForKey(courier.ConfigAPIKey, "") @@ -257,14 +257,14 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.Header.Set("X-API-TOKEN", token) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } externalID, err := jsonparser.GetString(respBody, "id") if err != nil { - logger.Error(errors.Errorf("unable to get id from body")) + clog.Error(errors.Errorf("unable to get id from body")) return status, nil } diff --git a/handlers/zenviaold/zenviaold.go b/handlers/zenviaold/zenviaold.go index d376931e3..bc979da77 100644 --- a/handlers/zenviaold/zenviaold.go +++ b/handlers/zenviaold/zenviaold.go @@ -115,7 +115,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // get our params payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) @@ -143,7 +143,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // get our params payload := &statusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) @@ -163,7 +163,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for ZV channel") @@ -195,7 +195,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.SetBasicAuth(username, password) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -204,7 +204,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha responseMsgStatus, _ := jsonparser.GetString(respBody, "sendSmsResponse", "statusCode") msgStatus, found := statusMapping[responseMsgStatus] if msgStatus == courier.MsgErrored || !found { - logger.Error(errors.Errorf("received non-success response: '%s'", responseMsgStatus)) + clog.Error(errors.Errorf("received non-success response: '%s'", responseMsgStatus)) return status, nil } diff --git a/sender.go b/sender.go index 06b4af714..1f5c1b0e2 100644 --- a/sender.go +++ b/sender.go @@ -189,7 +189,7 @@ func (w *Sender) sendMessage(msg Msg) { } var status MsgStatus - logger := NewChannelLogForSend(msg) + clog := NewChannelLogForSend(msg) if sent { // if this message was already sent, create a wired status for it @@ -197,13 +197,13 @@ func (w *Sender) sendMessage(msg Msg) { log.Warning("duplicate send, marking as wired") } else { // send our message - status, err = server.SendMsg(sendCTX, msg, logger) + status, err = server.SendMsg(sendCTX, msg, clog) duration := time.Since(start) secondDuration := float64(duration) / float64(time.Second) if err != nil { log.WithError(err).WithField("elapsed", duration).Error("error sending message") - logger.Error(err) + clog.Error(err) // possible for handlers to only return an error in which case we construct an error status if status == nil { @@ -231,7 +231,7 @@ func (w *Sender) sendMessage(msg Msg) { } // write our logs as well - err = backend.WriteChannelLog(writeCTX, logger) + err = backend.WriteChannelLog(writeCTX, clog) if err != nil { log.WithError(err).Info("error writing msg logs") } diff --git a/server.go b/server.go index fe0b4bffd..047c1c0e2 100644 --- a/server.go +++ b/server.go @@ -203,7 +203,7 @@ func (s *server) Stop() error { return nil } -func (s *server) SendMsg(ctx context.Context, msg Msg, logger *ChannelLogger) (MsgStatus, error) { +func (s *server) SendMsg(ctx context.Context, msg Msg, clog *ChannelLogger) (MsgStatus, error) { // find the handler for this message type handler, found := activeHandlers[msg.Channel().ChannelType()] if !found { @@ -211,7 +211,7 @@ func (s *server) SendMsg(ctx context.Context, msg Msg, logger *ChannelLogger) (M } // have the handler send it - return handler.Send(ctx, msg, logger) + return handler.Send(ctx, msg, clog) } func (s *server) WaitGroup() *sync.WaitGroup { return s.waitGroup } From bf2b170a29f338795d755ce15ade70d9ec02010f Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 24 Aug 2022 11:21:51 -0500 Subject: [PATCH 093/294] Rename remaining ChannelLogger variables --- backends/rapidpro/backend.go | 4 ++-- handlers/hormuud/hormuud.go | 4 ++-- handlers/i2sms/i2sms.go | 10 ++++---- handlers/infobip/infobip.go | 10 ++++---- handlers/jasmin/jasmin.go | 8 +++---- handlers/jiochat/jiochat.go | 12 +++++----- handlers/junebug/junebug.go | 10 ++++---- handlers/kaleyra/kaleyra.go | 18 +++++++-------- handlers/kannel/kannel.go | 10 ++++---- handlers/line/line.go | 8 +++---- handlers/m3tech/m3tech.go | 6 ++--- handlers/macrokiosk/macrokiosk.go | 8 +++---- handlers/mblox/mblox.go | 6 ++--- handlers/messangi/messangi.go | 14 +++++++----- handlers/mtarget/mtarget.go | 8 +++---- handlers/nexmo/nexmo.go | 10 ++++---- handlers/novo/novo.go | 8 +++---- handlers/playmobile/playmobile.go | 6 ++--- handlers/plivo/plivo.go | 8 +++---- handlers/redrabbit/redrabbit.go | 4 ++-- handlers/rocketchat/rocketchat.go | 6 ++--- handlers/shaqodoon/shaqodoon.go | 6 ++--- handlers/slack/slack.go | 38 +++++++++++++++---------------- handlers/smscentral/smscentral.go | 6 ++--- handlers/start/start.go | 6 ++--- handlers/telegram/telegram.go | 34 +++++++++++++-------------- handlers/thinq/thinq.go | 14 ++++++------ handlers/twiml/twiml.go | 12 +++++----- handlers/twitter/twitter.go | 28 +++++++++++------------ handlers/viber/viber.go | 12 +++++----- handlers/vk/vk.go | 16 ++++++------- handlers/wavy/wavy.go | 10 ++++---- handlers/wechat/wechat.go | 12 +++++----- handlers/whatsapp/whatsapp.go | 34 +++++++++++++-------------- test/backend.go | 4 ++-- 35 files changed, 206 insertions(+), 204 deletions(-) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 7a40cb5e2..79d80b564 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -380,11 +380,11 @@ func (b *backend) WriteChannelEvent(ctx context.Context, event courier.ChannelEv } // WriteChannelLog persists the passed in log to our database, for rapidpro we swallow all errors, logging isn't critical -func (b *backend) WriteChannelLog(ctx context.Context, log *courier.ChannelLogger) error { +func (b *backend) WriteChannelLog(ctx context.Context, clog *courier.ChannelLogger) error { timeout, cancel := context.WithTimeout(ctx, backendTimeout) defer cancel() - for _, l := range log.LegacyLogs() { + for _, l := range clog.LegacyLogs() { err := writeChannelLog(timeout, b, l) if err != nil { logrus.WithError(err).Error("error writing channel log") diff --git a/handlers/hormuud/hormuud.go b/handlers/hormuud/hormuud.go index afcdc3d23..09acebb7d 100644 --- a/handlers/hormuud/hormuud.go +++ b/handlers/hormuud/hormuud.go @@ -133,7 +133,7 @@ type tokenResponse struct { } // FetchToken gets the current token for this channel, either from Redis if cached or by requesting it -func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg courier.Msg, logger *courier.ChannelLogger) (string, error) { +func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg courier.Msg, clog *courier.ChannelLogger) (string, error) { // first check whether we have it in redis conn := h.Backend().RedisPool().Get() token, err := redis.String(conn.Do("GET", fmt.Sprintf("hm_token_%s", channel.UUID()))) @@ -166,7 +166,7 @@ func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg c req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return "", errors.Wrapf(err, "error making token request") } diff --git a/handlers/i2sms/i2sms.go b/handlers/i2sms/i2sms.go index bf14fdc71..cc3009811 100644 --- a/handlers/i2sms/i2sms.go +++ b/handlers/i2sms/i2sms.go @@ -42,7 +42,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receive is our handler for MO messages -func (h *handler) receive(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receive(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, err) @@ -83,7 +83,7 @@ type mtResponse struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for I2 channel") @@ -116,7 +116,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -125,7 +125,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha response := &mtResponse{} err = json.Unmarshal(respBody, response) if err != nil { - logger.Error(err) + clog.Error(err) break } @@ -135,7 +135,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha status.SetExternalID(response.Result.SessionID) } else { status.SetStatus(courier.MsgFailed) - logger.Error(fmt.Errorf("Received invalid response code: %s", response.ErrorCode)) + clog.Error(fmt.Errorf("Received invalid response code: %s", response.ErrorCode)) break } } diff --git a/handlers/infobip/infobip.go b/handlers/infobip/infobip.go index a805ee443..7773754b2 100644 --- a/handlers/infobip/infobip.go +++ b/handlers/infobip/infobip.go @@ -58,7 +58,7 @@ type ibStatus struct { } // statusMessage is our HTTP handler function for status updates -func (h *handler) statusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) statusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &statusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -126,7 +126,7 @@ type moMessage struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -175,7 +175,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for IB channel") @@ -227,14 +227,14 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } groupID, err := jsonparser.GetInt(respBody, "messages", "[0]", "status", "groupId") if err != nil || (groupID != 1 && groupID != 3) { - logger.Error(errors.Errorf("received error status: '%d'", groupID)) + clog.Error(errors.Errorf("received error status: '%d'", groupID)) return status, nil } diff --git a/handlers/jasmin/jasmin.go b/handlers/jasmin/jasmin.go index 3d67a5e16..c4b3dd9ab 100644 --- a/handlers/jasmin/jasmin.go +++ b/handlers/jasmin/jasmin.go @@ -43,7 +43,7 @@ type statusForm struct { } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -73,7 +73,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -119,7 +119,7 @@ func writeJasminACK(w http.ResponseWriter) error { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for JS channel") @@ -162,7 +162,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 6de7c3a20..055b17fa7 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -64,7 +64,7 @@ type verifyForm struct { } // VerifyURL is our HTTP handler function for Jiochat config URL verification callbacks -func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &verifyForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -109,7 +109,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -232,7 +232,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { accessToken, err := h.getAccessToken(msg.Channel()) if err != nil { return nil, err @@ -255,7 +255,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken)) - resp, _, err := handlers.RequestHTTP(req, logger) + resp, _, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -267,7 +267,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } // DescribeURN handles Jiochat contact details -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, logger *courier.ChannelLogger) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLogger) (map[string]string, error) { accessToken, err := h.getAccessToken(channel) if err != nil { return nil, err @@ -285,7 +285,7 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn req, _ := http.NewRequest(http.MethodGet, reqURL.String(), nil) req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken)) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("unable to look up contact data") } diff --git a/handlers/junebug/junebug.go b/handlers/junebug/junebug.go index a9a8fe3ab..e1a02465f 100644 --- a/handlers/junebug/junebug.go +++ b/handlers/junebug/junebug.go @@ -56,7 +56,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -108,7 +108,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveEvent is our HTTP handler function for incoming events -func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &eventPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -154,7 +154,7 @@ type mtPayload struct { EventAuthToken string `json:"event_auth_token,omitempty"` } -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { sendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, "") if sendURL == "" { return nil, fmt.Errorf("No send_url set for JN channel") @@ -197,14 +197,14 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.SetBasicAuth(username, password) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } externalID, err := jsonparser.GetString(respBody, "result", "message_id") if err != nil { - logger.Error(errors.Errorf("unable to get result.message_id from body")) + clog.Error(errors.Errorf("unable to get result.message_id from body")) return status, nil } diff --git a/handlers/kaleyra/kaleyra.go b/handlers/kaleyra/kaleyra.go index 8af1548dc..9af9adb89 100644 --- a/handlers/kaleyra/kaleyra.go +++ b/handlers/kaleyra/kaleyra.go @@ -65,7 +65,7 @@ type moStatusForm struct { } // receiveMsg is our HTTP handler function for incoming messages -func (h *handler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &moMsgForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -113,7 +113,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for outgoing messages statuses -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &moStatusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -137,7 +137,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { accountSID := msg.Channel().StringConfigForKey(configAccountSID, "") apiKey := msg.Channel().StringConfigForKey(configApiKey, "") @@ -160,7 +160,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha // download media req, _ := http.NewRequest(http.MethodGet, attachmentURL, nil) - resp, attBody, err := handlers.RequestHTTP(req, logger) + resp, attBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { kwaErr = errors.New("unable to fetch media") break @@ -174,7 +174,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha part, err := writer.CreateFormFile("media", fileName) _, err = io.Copy(part, bytes.NewReader(attBody)) if err != nil { - logger.Error(err) + clog.Error(err) kwaErr = err break } @@ -187,14 +187,14 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha for k, v := range baseForm { part, err := writer.CreateFormField(k) if err != nil { - logger.Error(err) + clog.Error(err) kwaErr = err break attachmentsLoop } _, err = part.Write([]byte(v)) if err != nil { - logger.Error(err) + clog.Error(err) kwaErr = err break attachmentsLoop } @@ -205,7 +205,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha // send multipart form req, _ = http.NewRequest(http.MethodPost, sendURL, body) req.Header.Set("Content-Type", writer.FormDataContentType()) - kwaResp, kwaRespBody, kwaErr = handlers.RequestHTTP(req, logger) + kwaResp, kwaRespBody, kwaErr = handlers.RequestHTTP(req, clog) } } else { form := url.Values{} @@ -221,7 +221,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req, _ := http.NewRequest(http.MethodPost, sendURL, strings.NewReader(form.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - kwaResp, kwaRespBody, kwaErr = handlers.RequestHTTP(req, logger) + kwaResp, kwaRespBody, kwaErr = handlers.RequestHTTP(req, clog) } if kwaErr != nil || kwaResp.StatusCode/100 != 2 { diff --git a/handlers/kannel/kannel.go b/handlers/kannel/kannel.go index 004c16e39..bf476d135 100644 --- a/handlers/kannel/kannel.go +++ b/handlers/kannel/kannel.go @@ -56,7 +56,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -94,7 +94,7 @@ type statusForm struct { } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -119,7 +119,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for KN channel") @@ -202,9 +202,9 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha var resp *http.Response if verifySSL { - resp, _, err = handlers.RequestHTTP(req, logger) + resp, _, err = handlers.RequestHTTP(req, clog) } else { - resp, _, err = handlers.RequestHTTPInsecure(req, logger) + resp, _, err = handlers.RequestHTTPInsecure(req, clog) } status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) diff --git a/handlers/line/line.go b/handlers/line/line.go index e5b46e3fc..cd6d3773d 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -112,7 +112,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { err := h.validateSignature(channel, r) if err != nil { return nil, err @@ -285,7 +285,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { authToken := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if authToken == "" { return nil, fmt.Errorf("no auth token set for LN channel: %s", msg.Channel().UUID()) @@ -362,7 +362,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return status, err } - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err == nil && resp.StatusCode/100 == 2 { batch = []string{} batchCount = 0 @@ -377,7 +377,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return status, err } - resp, _, err := handlers.RequestHTTP(req, logger) + resp, _, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/m3tech/m3tech.go b/handlers/m3tech/m3tech.go index 7033a014c..e8575b494 100644 --- a/handlers/m3tech/m3tech.go +++ b/handlers/m3tech/m3tech.go @@ -38,7 +38,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveMessage takes care of handling incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, err) @@ -69,7 +69,7 @@ func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWr } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for M3 channel") @@ -113,7 +113,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return nil, err } - resp, _, err := handlers.RequestHTTP(req, logger) + resp, _, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { break } diff --git a/handlers/macrokiosk/macrokiosk.go b/handlers/macrokiosk/macrokiosk.go index c01b57bfa..7e7ab4e99 100644 --- a/handlers/macrokiosk/macrokiosk.go +++ b/handlers/macrokiosk/macrokiosk.go @@ -61,7 +61,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -89,7 +89,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -152,7 +152,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") password := msg.Channel().StringConfigForKey(courier.ConfigPassword, "") servID := msg.Channel().StringConfigForKey(configMacrokioskServiceID, "") @@ -191,7 +191,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/mblox/mblox.go b/handlers/mblox/mblox.go index f049f0d06..c52ad82e9 100644 --- a/handlers/mblox/mblox.go +++ b/handlers/mblox/mblox.go @@ -60,7 +60,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveEvent is our HTTP handler function for incoming messages -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &eventPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -115,7 +115,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") password := msg.Channel().StringConfigForKey(courier.ConfigPassword, "") if username == "" || password == "" { @@ -143,7 +143,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", password)) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/messangi/messangi.go b/handlers/messangi/messangi.go index 3394b291e..833ce890e 100644 --- a/handlers/messangi/messangi.go +++ b/handlers/messangi/messangi.go @@ -46,11 +46,13 @@ func (h *handler) Initialize(s courier.Server) error { return nil } -// +// +// // sendMT // OK // Completed -// +// +// type mtResponse struct { Input string `xml:"input"` Status string `xml:"status"` @@ -58,7 +60,7 @@ type mtResponse struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { publicKey := msg.Channel().StringConfigForKey(configPublicKey, "") if publicKey == "" { return nil, fmt.Errorf("no public_key set for MG channel") @@ -94,7 +96,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return nil, err } - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -103,7 +105,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha response := &mtResponse{} err = xml.Unmarshal(respBody, response) if err != nil { - logger.Error(err) + clog.Error(err) break } @@ -112,7 +114,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha status.SetStatus(courier.MsgWired) } else { status.SetStatus(courier.MsgFailed) - logger.Error(fmt.Errorf("Received invalid response description: %s", response.Description)) + clog.Error(fmt.Errorf("Received invalid response description: %s", response.Description)) break } } diff --git a/handlers/mtarget/mtarget.go b/handlers/mtarget/mtarget.go index 85d45b3f2..acb167fa9 100644 --- a/handlers/mtarget/mtarget.go +++ b/handlers/mtarget/mtarget.go @@ -52,7 +52,7 @@ func (h *handler) Initialize(s courier.Server) error { } // ReceiveMsg handles both MO messages and Stop commands -func (h *handler) receiveMsg(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMsg(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, err) @@ -148,7 +148,7 @@ func (h *handler) receiveMsg(ctx context.Context, c courier.Channel, w http.Resp } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for MT channel") @@ -179,7 +179,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return nil, err } - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -202,7 +202,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha status.SetExternalID(externalID) } else { status.SetStatus(courier.MsgFailed) - logger.Error(fmt.Errorf("Error status code, failing permanently")) + clog.Error(fmt.Errorf("Error status code, failing permanently")) break } } diff --git a/handlers/nexmo/nexmo.go b/handlers/nexmo/nexmo.go index ee6e46951..a5829ab0c 100644 --- a/handlers/nexmo/nexmo.go +++ b/handlers/nexmo/nexmo.go @@ -70,7 +70,7 @@ var statusMappings = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &statusForm{} handlers.DecodeAndValidateForm(form, r) @@ -96,7 +96,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} handlers.DecodeAndValidateForm(form, r) @@ -117,7 +117,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { nexmoAPIKey := msg.Channel().StringConfigForKey(configNexmoAPIKey, "") if nexmoAPIKey == "" { return nil, fmt.Errorf("no nexmo API key set for NX channel") @@ -163,7 +163,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - resp, respBody, requestErr = handlers.RequestHTTP(req, logger) + resp, respBody, requestErr = handlers.RequestHTTP(req, clog) matched := throttledRE.FindAllStringSubmatch(string(respBody), -1) if len(matched) > 0 && len(matched[0]) > 0 { sleepTime, _ := strconv.Atoi(matched[0][1]) @@ -179,7 +179,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha nexmoStatus, err := jsonparser.GetString(respBody, "messages", "[0]", "status") if err != nil || nexmoStatus != "0" { - logger.Error(errors.Errorf("failed to send message, received error status [%s]", nexmoStatus)) + clog.Error(errors.Errorf("failed to send message, received error status [%s]", nexmoStatus)) return status, nil } diff --git a/handlers/novo/novo.go b/handlers/novo/novo.go index 84cf820bf..9d72baf19 100644 --- a/handlers/novo/novo.go +++ b/handlers/novo/novo.go @@ -45,7 +45,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // check authentication secret := c.StringConfigForKey(courier.ConfigSecret, "") if secret != "" { @@ -78,7 +78,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { merchantID := msg.Channel().StringConfigForKey(configMerchantId, "") if merchantID == "" { return nil, fmt.Errorf("no merchant_id set for NV channel") @@ -110,7 +110,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return nil, err } - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -122,7 +122,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha status.SetStatus(courier.MsgWired) } else { status.SetStatus(courier.MsgFailed) - logger.Error(fmt.Errorf("received invalid response")) + clog.Error(fmt.Errorf("received invalid response")) break } } diff --git a/handlers/playmobile/playmobile.go b/handlers/playmobile/playmobile.go index 69835dc34..5592bf89d 100644 --- a/handlers/playmobile/playmobile.go +++ b/handlers/playmobile/playmobile.go @@ -92,7 +92,7 @@ type mtResponse struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &mtResponse{} err := handlers.DecodeAndValidateXML(payload, r) @@ -145,7 +145,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(configUsername, "") if username == "" { return nil, fmt.Errorf("no username set for PM channel") @@ -196,7 +196,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, _, err := handlers.RequestHTTP(req, logger) + resp, _, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/plivo/plivo.go b/handlers/plivo/plivo.go index bc1d6d6d7..12fc6c255 100644 --- a/handlers/plivo/plivo.go +++ b/handlers/plivo/plivo.go @@ -70,7 +70,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -104,7 +104,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -136,7 +136,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { authID := msg.Channel().StringConfigForKey(configPlivoAuthID, "") authToken := msg.Channel().StringConfigForKey(configPlivoAuthToken, "") plivoAppID := msg.Channel().StringConfigForKey(configPlivoAPPID, "") @@ -170,7 +170,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.SetBasicAuth(authID, authToken) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/redrabbit/redrabbit.go b/handlers/redrabbit/redrabbit.go index b96f29de1..503a7e397 100644 --- a/handlers/redrabbit/redrabbit.go +++ b/handlers/redrabbit/redrabbit.go @@ -36,7 +36,7 @@ func (h *handler) Initialize(s courier.Server) error { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") password := msg.Channel().StringConfigForKey(courier.ConfigPassword, "") if username == "" || password == "" { @@ -72,7 +72,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return nil, err } - resp, _, err := handlers.RequestHTTP(req, logger) + resp, _, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/rocketchat/rocketchat.go b/handlers/rocketchat/rocketchat.go index 9ec97088d..7e8e564fb 100644 --- a/handlers/rocketchat/rocketchat.go +++ b/handlers/rocketchat/rocketchat.go @@ -57,7 +57,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // check authorization secret := channel.StringConfigForKey(configSecret, "") if fmt.Sprintf("Token %s", secret) != r.Header.Get("Authorization") { @@ -109,7 +109,7 @@ type mtPayload struct { Attachments []Attachment `json:"attachments,omitempty"` } -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { baseURL := msg.Channel().StringConfigForKey(configBaseURL, "") secret := msg.Channel().StringConfigForKey(configSecret, "") botUsername := msg.Channel().StringConfigForKey(configBotUsername, "") @@ -139,7 +139,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Token %s", secret)) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/shaqodoon/shaqodoon.go b/handlers/shaqodoon/shaqodoon.go index 7ed8989c5..a619ab232 100644 --- a/handlers/shaqodoon/shaqodoon.go +++ b/handlers/shaqodoon/shaqodoon.go @@ -45,7 +45,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -84,7 +84,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { sendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, "") if sendURL == "" { return nil, fmt.Errorf("missing send_url for SQ channel") @@ -116,7 +116,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) - resp, _, err := handlers.RequestHTTPInsecure(req, logger) + resp, _, err := handlers.RequestHTTPInsecure(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index 39a2e28ef..16adbde53 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -62,7 +62,7 @@ func handleURLVerification(ctx context.Context, channel courier.Channel, w http. return nil, nil } -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -85,7 +85,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h attachmentURLs := make([]string, 0) for _, file := range payload.Event.Files { - fileURL, err := h.resolveFile(ctx, channel, file, logger) + fileURL, err := h.resolveFile(ctx, channel, file, clog) if err != nil { courier.LogRequestError(r, channel, err) } else { @@ -105,7 +105,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "Ignoring request, no message") } -func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file File, logger *courier.ChannelLogger) (string, error) { +func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file File, clog *courier.ChannelLogger) (string, error) { userToken := channel.StringConfigForKey(configUserToken, "") fileApiURL := apiURL + "/files.sharedPublicURL" @@ -119,7 +119,7 @@ func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file req.Header.Add("Content-Type", "application/json; charset=utf-8") req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", userToken)) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return "", errors.New("unable to resolve file") } @@ -148,7 +148,7 @@ func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file return filePath, nil } -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { botToken := msg.Channel().StringConfigForKey(configBotToken, "") if botToken == "" { return nil, fmt.Errorf("missing bot token for SL/slack channel") @@ -157,25 +157,25 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) for _, attachment := range msg.Attachments() { - fileAttachment, err := parseAttachmentToFileParams(msg, attachment, logger) + fileAttachment, err := parseAttachmentToFileParams(msg, attachment, clog) if err != nil { - logger.Error(err) + clog.Error(err) return status, nil } if fileAttachment != nil { - err = sendFilePart(msg, botToken, fileAttachment, logger) + err = sendFilePart(msg, botToken, fileAttachment, clog) if err != nil { - logger.Error(err) + clog.Error(err) return status, nil } } } if msg.Text() != "" { - err := sendTextMsgPart(msg, botToken, logger) + err := sendTextMsgPart(msg, botToken, clog) if err != nil { - logger.Error(err) + clog.Error(err) return status, nil } } @@ -184,7 +184,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return status, nil } -func sendTextMsgPart(msg courier.Msg, token string, logger *courier.ChannelLogger) error { +func sendTextMsgPart(msg courier.Msg, token string, clog *courier.ChannelLogger) error { sendURL := apiURL + "/chat.postMessage" msgPayload := &mtPayload{ @@ -204,7 +204,7 @@ func sendTextMsgPart(msg courier.Msg, token string, logger *courier.ChannelLogge req.Header.Set("Content-Type", "application/json; charset=utf-8") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return errors.New("error sending message") } @@ -224,7 +224,7 @@ func sendTextMsgPart(msg courier.Msg, token string, logger *courier.ChannelLogge return nil } -func parseAttachmentToFileParams(msg courier.Msg, attachment string, logger *courier.ChannelLogger) (*FileParams, error) { +func parseAttachmentToFileParams(msg courier.Msg, attachment string, clog *courier.ChannelLogger) (*FileParams, error) { _, attURL := handlers.SplitAttachment(attachment) req, err := http.NewRequest(http.MethodGet, attURL, nil) @@ -232,7 +232,7 @@ func parseAttachmentToFileParams(msg courier.Msg, attachment string, logger *cou return nil, errors.Wrapf(err, "error building file request") } - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("error fetching attachment") } @@ -244,7 +244,7 @@ func parseAttachmentToFileParams(msg courier.Msg, attachment string, logger *cou return &FileParams{File: respBody, FileName: filename, Channels: msg.URN().Path()}, nil } -func sendFilePart(msg courier.Msg, token string, fileParams *FileParams, logger *courier.ChannelLogger) error { +func sendFilePart(msg courier.Msg, token string, fileParams *FileParams, clog *courier.ChannelLogger) error { uploadURL := apiURL + "/files.upload" body := &bytes.Buffer{} @@ -276,7 +276,7 @@ func sendFilePart(msg courier.Msg, token string, fileParams *FileParams, logger req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) req.Header.Add("Content-Type", writer.FormDataContentType()) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return errors.New("error uploading file to slack") } @@ -294,7 +294,7 @@ func sendFilePart(msg courier.Msg, token string, fileParams *FileParams, logger } // DescribeURN handles Slack user details -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, logger *courier.ChannelLogger) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLogger) (map[string]string, error) { resource := "/users.info" urlStr := apiURL + resource @@ -307,7 +307,7 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn q.Add("user", urn.Path()) req.URL.RawQuery = q.Encode() - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("unable to look up user info") } diff --git a/handlers/smscentral/smscentral.go b/handlers/smscentral/smscentral.go index 58a282839..8c19150e7 100644 --- a/handlers/smscentral/smscentral.go +++ b/handlers/smscentral/smscentral.go @@ -43,7 +43,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -63,7 +63,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for SC channel") @@ -90,7 +90,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - resp, _, err := handlers.RequestHTTP(req, logger) + resp, _, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/start/start.go b/handlers/start/start.go index cc0cad359..987f525bc 100644 --- a/handlers/start/start.go +++ b/handlers/start/start.go @@ -56,7 +56,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateXML(payload, r) if err != nil { @@ -120,7 +120,7 @@ type mtResponse struct { State string `xml:"state"` } -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for ST channel: %s", msg.Channel().UUID()) @@ -163,7 +163,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/xml; charset=utf8") req.SetBasicAuth(username, password) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index 5c95b0d0a..8f75186cb 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -49,7 +49,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -102,15 +102,15 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } photo = payload.Message.Photo[i] } - mediaURL, err = h.resolveFileID(ctx, channel, photo.FileID, logger) + mediaURL, err = h.resolveFileID(ctx, channel, photo.FileID, clog) } else if payload.Message.Video != nil { - mediaURL, err = h.resolveFileID(ctx, channel, payload.Message.Video.FileID, logger) + mediaURL, err = h.resolveFileID(ctx, channel, payload.Message.Video.FileID, clog) } else if payload.Message.Voice != nil { - mediaURL, err = h.resolveFileID(ctx, channel, payload.Message.Voice.FileID, logger) + mediaURL, err = h.resolveFileID(ctx, channel, payload.Message.Voice.FileID, clog) } else if payload.Message.Sticker != nil { - mediaURL, err = h.resolveFileID(ctx, channel, payload.Message.Sticker.Thumb.FileID, logger) + mediaURL, err = h.resolveFileID(ctx, channel, payload.Message.Sticker.Thumb.FileID, clog) } else if payload.Message.Document != nil { - mediaURL, err = h.resolveFileID(ctx, channel, payload.Message.Document.FileID, logger) + mediaURL, err = h.resolveFileID(ctx, channel, payload.Message.Document.FileID, clog) } else if payload.Message.Venue != nil { text = utils.JoinNonEmpty(", ", payload.Message.Venue.Title, payload.Message.Venue.Address) mediaURL = fmt.Sprintf("geo:%f,%f", payload.Message.Location.Latitude, payload.Message.Location.Longitude) @@ -149,7 +149,7 @@ type mtResponse struct { } `json:"result"` } -func (h *handler) sendMsgPart(msg courier.Msg, token string, path string, form url.Values, keyboard *ReplyKeyboardMarkup, logger *courier.ChannelLogger) (string, bool, error) { +func (h *handler) sendMsgPart(msg courier.Msg, token string, path string, form url.Values, keyboard *ReplyKeyboardMarkup, clog *courier.ChannelLogger) (string, bool, error) { // either include or remove our keyboard if keyboard == nil { form.Add("reply_markup", `{"remove_keyboard":true}`) @@ -164,7 +164,7 @@ func (h *handler) sendMsgPart(msg courier.Msg, token string, path string, form u } req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - resp, respBody, _ := handlers.RequestHTTP(req, logger) + resp, respBody, _ := handlers.RequestHTTP(req, clog) response := &mtResponse{} err = json.Unmarshal(respBody, response) @@ -184,7 +184,7 @@ func (h *handler) sendMsgPart(msg courier.Msg, token string, path string, form u } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { confAuth := msg.Channel().ConfigForKey(courier.ConfigAuthToken, "") authToken, isStr := confAuth.(string) if !isStr || authToken == "" { @@ -227,7 +227,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha "text": []string{msg.Text()}, } - externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendMessage", form, msgKeyBoard, logger) + externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendMessage", form, msgKeyBoard, clog) if botBlocked { status.SetStatus(courier.MsgFailed) channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) @@ -253,7 +253,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha "photo": []string{attachment.URL}, "caption": []string{caption}, } - externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendPhoto", form, attachmentKeyBoard, logger) + externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendPhoto", form, attachmentKeyBoard, clog) if botBlocked { status.SetStatus(courier.MsgFailed) channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) @@ -269,7 +269,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha "video": []string{attachment.URL}, "caption": []string{caption}, } - externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendVideo", form, attachmentKeyBoard, logger) + externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendVideo", form, attachmentKeyBoard, clog) if botBlocked { status.SetStatus(courier.MsgFailed) channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) @@ -285,7 +285,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha "audio": []string{attachment.URL}, "caption": []string{caption}, } - externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendAudio", form, attachmentKeyBoard, logger) + externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendAudio", form, attachmentKeyBoard, clog) if botBlocked { status.SetStatus(courier.MsgFailed) channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) @@ -301,7 +301,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha "document": []string{attachment.URL}, "caption": []string{caption}, } - externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendDocument", form, attachmentKeyBoard, logger) + externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendDocument", form, attachmentKeyBoard, clog) if botBlocked { status.SetStatus(courier.MsgFailed) channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) @@ -312,7 +312,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha hasError = err != nil default: - logger.Error(fmt.Errorf("unknown attachment content type: %s", attachment.ContentType)) + clog.Error(fmt.Errorf("unknown attachment content type: %s", attachment.ContentType)) hasError = true } } @@ -324,7 +324,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return status, nil } -func (h *handler) resolveFileID(ctx context.Context, channel courier.Channel, fileID string, logger *courier.ChannelLogger) (string, error) { +func (h *handler) resolveFileID(ctx context.Context, channel courier.Channel, fileID string, clog *courier.ChannelLogger) (string, error) { confAuth := channel.ConfigForKey(courier.ConfigAuthToken, "") authToken, isStr := confAuth.(string) if !isStr || authToken == "" { @@ -343,7 +343,7 @@ func (h *handler) resolveFileID(ctx context.Context, channel courier.Channel, fi courier.LogRequestError(req, channel, err) } - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return "", errors.New("unable to resolve file") } diff --git a/handlers/thinq/thinq.go b/handlers/thinq/thinq.go index 100e3fae0..febc6379d 100644 --- a/handlers/thinq/thinq.go +++ b/handlers/thinq/thinq.go @@ -55,7 +55,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -103,7 +103,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // get our params form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -129,7 +129,7 @@ type mtMessage struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { accountID := msg.Channel().StringConfigForKey(configAccountID, "") if accountID == "" { return nil, fmt.Errorf("no account id set for TQ channel") @@ -166,7 +166,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.SetBasicAuth(tokenUser, token) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -174,7 +174,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha // try to get our external id externalID, err := jsonparser.GetString(respBody, "guid") if err != nil { - logger.Error(errors.New("Unable to read external ID")) + clog.Error(errors.New("Unable to read external ID")) return status, nil } status.SetStatus(courier.MsgWired) @@ -199,7 +199,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Accept", "application/json") req.SetBasicAuth(tokenUser, token) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -207,7 +207,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha // get our external id externalID, err := jsonparser.GetString(respBody, "guid") if err != nil { - logger.Error(errors.New("Unable to read external ID from guid field")) + clog.Error(errors.New("Unable to read external ID from guid field")) return status, nil } diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index 8760dc470..c992af303 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -100,7 +100,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { err := h.validateSignature(channel, r) if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) @@ -140,7 +140,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { err := h.validateSignature(channel, r) if err != nil { return nil, err @@ -200,7 +200,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { // build our callback URL callbackDomain := msg.Channel().CallbackDomain(h.Server().Config().Domain) callbackURL := fmt.Sprintf("https://%s/c/%s/%s/status?id=%d&action=callback", callbackDomain, strings.ToLower(h.ChannelType().String()), msg.Channel().UUID(), msg.ID()) @@ -266,7 +266,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil { return status, nil } @@ -285,7 +285,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return nil, err } } - logger.Error(errors.Errorf("received error code from twilio '%d'", errorCode)) + clog.Error(errors.Errorf("received error code from twilio '%d'", errorCode)) return status, nil } } @@ -293,7 +293,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha // grab the external id externalID, err := jsonparser.GetString(respBody, "sid") if err != nil { - logger.Error(errors.Errorf("unable to get sid from body")) + clog.Error(errors.Errorf("unable to get sid from body")) return status, nil } diff --git a/handlers/twitter/twitter.go b/handlers/twitter/twitter.go index 35cb8b238..0dd627203 100644 --- a/handlers/twitter/twitter.go +++ b/handlers/twitter/twitter.go @@ -65,7 +65,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveVerify handles Twitter's webhook verification callback -func (h *handler) receiveVerify(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveVerify(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { crcToken := r.URL.Query().Get("crc_token") if crcToken == "" { return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, fmt.Errorf(`missing required 'crc_token' query parameter`)) @@ -134,7 +134,7 @@ type moPayload struct { } // receiveEvent is our HTTP handler function for incoming events -func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // read our handle id handleID := c.StringConfigForKey(configHandleID, "") if handleID == "" { @@ -255,7 +255,7 @@ type mtAttachment struct { } `json:"media"` } -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { apiKey := msg.Channel().StringConfigForKey(configAPIKey, "") apiSecret := msg.Channel().StringConfigForKey(configAPISecret, "") accessToken := msg.Channel().StringConfigForKey(configAccessToken, "") @@ -295,12 +295,12 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha mimeType, s3url := handlers.SplitAttachment(attachment) mediaID := "" if strings.HasPrefix(mimeType, "image") || strings.HasPrefix(mimeType, "video") { - mediaID, err = uploadMediaToTwitter(msg, mediaURL, mimeType, s3url, client, logger) + mediaID, err = uploadMediaToTwitter(msg, mediaURL, mimeType, s3url, client, clog) if err != nil { - logger.Error(errors.Wrap(err, "unable to upload media to Twitter server")) + clog.Error(errors.Wrap(err, "unable to upload media to Twitter server")) } } else { - logger.Error(errors.New("unable to upload media, unsupported Twitter attachment")) + clog.Error(errors.New("unable to upload media, unsupported Twitter attachment")) } if mediaID != "" { @@ -338,14 +338,14 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTPWithClient(client, req, logger) + resp, respBody, err := handlers.RequestHTTPWithClient(client, req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } externalID, err := jsonparser.GetString(respBody, "event", "id") if err != nil { - logger.Error(errors.Errorf("unable to get message_id from body")) + clog.Error(errors.Errorf("unable to get message_id from body")) return status, nil } @@ -370,11 +370,11 @@ func generateSignature(secret string, content string) string { return base64.StdEncoding.EncodeToString(h.Sum(nil)) } -func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType string, attachmentURL string, client *http.Client, logger *courier.ChannelLogger) (string, error) { +func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType string, attachmentURL string, client *http.Client, clog *courier.ChannelLogger) (string, error) { // retrieve the media to be sent from S3 req, _ := http.NewRequest(http.MethodGet, attachmentURL, nil) - s3Resp, s3RespBody, err := handlers.RequestHTTP(req, logger) + s3Resp, s3RespBody, err := handlers.RequestHTTP(req, clog) if err != nil || s3Resp.StatusCode/100 != 2 { return "", err } @@ -404,7 +404,7 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s twReq.Header.Set("Accept", "application/json") twReq.Header.Set("User-Agent", utils.HTTPUserAgent) - twResp, twRespBody, err := handlers.RequestHTTPWithClient(client, twReq, logger) + twResp, twRespBody, err := handlers.RequestHTTPWithClient(client, twReq, clog) if err != nil || twResp.StatusCode/100 != 2 { return "", err } @@ -447,7 +447,7 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s twReq.Header.Set("Accept", "application/json") twReq.Header.Set("User-Agent", utils.HTTPUserAgent) - twResp, twRespBody, err = handlers.RequestHTTPWithClient(client, twReq, logger) + twResp, twRespBody, err = handlers.RequestHTTPWithClient(client, twReq, clog) if err != nil || twResp.StatusCode/100 != 2 { return "", err } @@ -466,7 +466,7 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s twReq.Header.Set("Accept", "application/json") twReq.Header.Set("User-Agent", utils.HTTPUserAgent) - twResp, twRespBody, err = handlers.RequestHTTPWithClient(client, twReq, logger) + twResp, twRespBody, err = handlers.RequestHTTPWithClient(client, twReq, clog) if err != nil || twResp.StatusCode/100 != 2 { return "", err } @@ -497,7 +497,7 @@ func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType s twReq.Header.Set("Accept", "application/json") twReq.Header.Set("User-Agent", utils.HTTPUserAgent) - twResp, twRespBody, err = handlers.RequestHTTPWithClient(client, twReq, logger) + twResp, twRespBody, err = handlers.RequestHTTPWithClient(client, twReq, clog) if err != nil || twResp.StatusCode/100 != 2 { return "", err } diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index 6f4c571e2..2e0011416 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -89,7 +89,7 @@ type welcomeMessagePayload struct { } // receiveEvent is our HTTP handler function for incoming messages -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { err := h.validateSignature(channel, r) if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) @@ -309,7 +309,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { authToken := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if authToken == "" { return nil, fmt.Errorf("missing auth token in config") @@ -375,7 +375,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha msgText = "" default: - logger.Error(fmt.Errorf("unknown media type: %s", mediaType)) + clog.Error(fmt.Errorf("unknown media type: %s", mediaType)) } } else { @@ -411,17 +411,17 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } responseStatus, err := jsonparser.GetInt(respBody, "status") if err != nil { - logger.Error(errors.Errorf("received invalid JSON response")) + clog.Error(errors.Errorf("received invalid JSON response")) return status, nil } if responseStatus != 0 { - logger.Error(errors.Errorf("received non-0 status: '%d'", responseStatus)) + clog.Error(errors.Errorf("received non-0 status: '%d'", responseStatus)) return status, nil } diff --git a/handlers/vk/vk.go b/handlers/vk/vk.go index fc357d743..2f556390e 100644 --- a/handlers/vk/vk.go +++ b/handlers/vk/vk.go @@ -193,7 +193,7 @@ type mediaUploadInfoPayload struct { } // receiveEvent handles request event type -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { // read request body bodyBytes, err := ioutil.ReadAll(io.LimitReader(r.Body, 100000)) @@ -273,7 +273,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // DescribeURN handles VK contact details -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, logger *courier.ChannelLogger) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLogger) (map[string]string, error) { req, err := http.NewRequest(http.MethodPost, apiBaseURL+actionGetUser, nil) if err != nil { return nil, err @@ -285,7 +285,7 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn req.URL.RawQuery = params.Encode() - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("unable to look up user info") } @@ -386,14 +386,14 @@ func takeFirstAttachmentUrl(payload moNewMessagePayload) string { return "" } -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) params := buildApiBaseParams(msg.Channel()) params.Set(paramUserId, msg.URN().Path()) params.Set(paramRandomId, msg.ID().String()) - text, attachments := buildTextAndAttachmentParams(msg, logger) + text, attachments := buildTextAndAttachmentParams(msg, clog) params.Set(paramMessage, text) params.Set(paramAttachments, attachments) @@ -411,7 +411,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.URL.RawQuery = params.Encode() - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -428,7 +428,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } // buildTextAndAttachmentParams builds msg text with attachment links (if needed) and attachments list param, also returns the errors that occurred -func buildTextAndAttachmentParams(msg courier.Msg, logger *courier.ChannelLogger) (string, string) { +func buildTextAndAttachmentParams(msg courier.Msg, clog *courier.ChannelLogger) (string, string) { var msgAttachments []string textBuf := bytes.Buffer{} @@ -449,7 +449,7 @@ func buildTextAndAttachmentParams(msg courier.Msg, logger *courier.ChannelLogger if attachment, err := handleMediaUploadAndGetAttachment(msg.Channel(), mediaTypeImage, mediaExt, mediaURL); err == nil { msgAttachments = append(msgAttachments, attachment) } else { - logger.Error(err) + clog.Error(err) } default: diff --git a/handlers/wavy/wavy.go b/handlers/wavy/wavy.go index 87b215fc3..0daff36c3 100644 --- a/handlers/wavy/wavy.go +++ b/handlers/wavy/wavy.go @@ -62,7 +62,7 @@ type sentStatusPayload struct { } // sentStatusMessage is our HTTP handler function for status updates -func (h *handler) sentStatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) sentStatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &sentStatusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -85,7 +85,7 @@ type deliveredStatusPayload struct { } // sentStatusMessage is our HTTP handler function for status updates -func (h *handler) deliveredStatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) deliveredStatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &deliveredStatusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -111,7 +111,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -139,7 +139,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for %s channel", msg.Channel().ChannelType()) @@ -170,7 +170,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("username", username) req.Header.Set("authenticationtoken", token) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index 97e9daca8..3d56dd3f7 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -61,7 +61,7 @@ type verifyForm struct { } // VerifyURL is our HTTP handler function for WeChat config URL verification callbacks -func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { form := &verifyForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -166,7 +166,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateXML(payload, r) if err != nil { @@ -233,7 +233,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { accessToken, err := h.getAccessToken(msg.Channel()) if err != nil { return nil, err @@ -265,7 +265,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, _, err := handlers.RequestHTTP(req, logger) + resp, _, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -277,7 +277,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha } // DescribeURN handles WeChat contact details -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, logger *courier.ChannelLogger) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLogger) (map[string]string, error) { accessToken, err := h.getAccessToken(channel) if err != nil { return nil, err @@ -295,7 +295,7 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn req, _ := http.NewRequest(http.MethodGet, reqURL.String(), nil) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("unable to look up contact data") } diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index 5d9ccd4c5..0f900e765 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -172,7 +172,7 @@ type eventPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, logger *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { payload := &eventPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -496,7 +496,7 @@ type mtErrorPayload struct { const maxMsgLength = 4096 // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { conn := h.Backend().RedisPool().Get() defer conn.Close() @@ -517,7 +517,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha var wppID string - payloads, err := buildPayloads(msg, h, logger) + payloads, err := buildPayloads(msg, h, clog) fail := payloads == nil && err != nil if fail { @@ -526,7 +526,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha for i, payload := range payloads { externalID := "" - wppID, externalID, err = sendWhatsAppMsg(conn, msg, sendPath, payload, logger) + wppID, externalID, err = sendWhatsAppMsg(conn, msg, sendPath, payload, clog) if err != nil { break } @@ -545,7 +545,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha err = status.SetUpdatedURN(msg.URN(), newURN) if err != nil { - logger.Error(err) + clog.Error(err) } } status.SetStatus(courier.MsgWired) @@ -554,7 +554,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, logger *courier.Cha return status, nil } -func buildPayloads(msg courier.Msg, h *handler, logger *courier.ChannelLogger) ([]interface{}, error) { +func buildPayloads(msg courier.Msg, h *handler, clog *courier.ChannelLogger) ([]interface{}, error) { var payloads []interface{} var err error @@ -571,7 +571,7 @@ func buildPayloads(msg courier.Msg, h *handler, logger *courier.ChannelLogger) ( for attachmentCount, attachment := range msg.Attachments() { mimeType, mediaURL := handlers.SplitAttachment(attachment) - mediaID, err := h.fetchMediaID(msg, mimeType, mediaURL, logger) + mediaID, err := h.fetchMediaID(msg, mimeType, mediaURL, clog) if err != nil { logrus.WithField("channel_uuid", msg.Channel().UUID().String()).WithError(err).Error("error while uploading media to whatsapp") } @@ -627,7 +627,7 @@ func buildPayloads(msg courier.Msg, h *handler, logger *courier.ChannelLogger) ( payload.Video = mediaPayload payloads = append(payloads, payload) } else { - logger.Error(fmt.Errorf("unknown attachment mime type: %s", mimeType)) + clog.Error(fmt.Errorf("unknown attachment mime type: %s", mimeType)) break } } @@ -834,7 +834,7 @@ func buildPayloads(msg courier.Msg, h *handler, logger *courier.ChannelLogger) ( } // fetchMediaID tries to fetch the id for the uploaded media, setting the result in redis. -func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string, logger *courier.ChannelLogger) (string, error) { +func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string, clog *courier.ChannelLogger) (string, error) { // check in cache first rc := h.Backend().RedisPool().Get() defer rc.Close() @@ -863,7 +863,7 @@ func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string, logge return "", errors.Wrapf(err, "error building media request") } - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { failedMediaCache.Set(failKey, true, cache.DefaultExpiration) return "", nil @@ -884,7 +884,7 @@ func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string, logge setWhatsAppAuthHeader(&req.Header, msg.Channel()) req.Header.Add("Content-Type", httpx.DetectContentType(respBody)) - resp, respBody, err = handlers.RequestHTTP(req, logger) + resp, respBody, err = handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { failedMediaCache.Set(failKey, true, cache.DefaultExpiration) return "", errors.Wrapf(err, "error uploading media to whatsapp") @@ -905,7 +905,7 @@ func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string, logge return mediaID, nil } -func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload interface{}, logger *courier.ChannelLogger) (string, string, error) { +func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload interface{}, clog *courier.ChannelLogger) (string, string, error) { jsonBody, err := json.Marshal(payload) if err != nil { @@ -914,7 +914,7 @@ func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload req, _ := http.NewRequest(http.MethodPost, sendPath.String(), bytes.NewReader(jsonBody)) req.Header = buildWhatsAppHeaders(msg.Channel()) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil { return "", "", err } @@ -954,7 +954,7 @@ func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload } // check contact baseURL := fmt.Sprintf("%s://%s", sendPath.Scheme, sendPath.Host) - checkResp, err := checkWhatsAppContact(msg.Channel(), baseURL, msg.URN(), logger) + checkResp, err := checkWhatsAppContact(msg.Channel(), baseURL, msg.URN(), clog) if checkResp == nil { return "", "", err } @@ -1012,7 +1012,7 @@ func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload reqRetry.URL.RawQuery = fmt.Sprintf("%s=1", retryParam) } - retryResp, retryRespBody, err := handlers.RequestHTTP(reqRetry, logger) + retryResp, retryRespBody, err := handlers.RequestHTTP(reqRetry, clog) if err != nil || retryResp.StatusCode/100 != 2 { return "", "", errors.New("error making retry request") } @@ -1082,7 +1082,7 @@ type mtContactCheckPayload struct { ForceCheck bool `json:"force_check"` } -func checkWhatsAppContact(channel courier.Channel, baseURL string, urn urns.URN, logger *courier.ChannelLogger) ([]byte, error) { +func checkWhatsAppContact(channel courier.Channel, baseURL string, urn urns.URN, clog *courier.ChannelLogger) ([]byte, error) { payload := mtContactCheckPayload{ Blocking: "wait", Contacts: []string{fmt.Sprintf("+%s", urn.Path())}, @@ -1097,7 +1097,7 @@ func checkWhatsAppContact(channel courier.Channel, baseURL string, urn urns.URN, req, _ := http.NewRequest(http.MethodPost, sendURL, bytes.NewReader(reqBody)) req.Header = buildWhatsAppHeaders(channel) - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("error checking contact") } diff --git a/test/backend.go b/test/backend.go index fb444f06d..546a438d1 100644 --- a/test/backend.go +++ b/test/backend.go @@ -182,11 +182,11 @@ func (mb *MockBackend) MarkOutgoingMsgComplete(ctx context.Context, msg courier. } // WriteChannelLog writes the passed in channel log to the DB -func (mb *MockBackend) WriteChannelLog(ctx context.Context, log *courier.ChannelLogger) error { +func (mb *MockBackend) WriteChannelLog(ctx context.Context, clog *courier.ChannelLogger) error { mb.mutex.Lock() defer mb.mutex.Unlock() - mb.channelLogs = append(mb.channelLogs, log) + mb.channelLogs = append(mb.channelLogs, clog) return nil } From b88185a897cce6ac1cadebc560ed7426acf5f503 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 24 Aug 2022 11:56:08 -0500 Subject: [PATCH 094/294] Update CHANGELOG.md for v7.5.15 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d154aec97..cf8527737 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.15 +---------- + * Use logger for handler func calls + v7.5.14 ---------- * Update to latest gocommon and use new recorder reconstruct option From 4339a8fba83e52b8a89d10df398468389bd9753c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 24 Aug 2022 14:26:17 -0500 Subject: [PATCH 095/294] Write channel logs in new format --- backends/rapidpro/backend.go | 9 +- backends/rapidpro/backend_test.go | 7 +- backends/rapidpro/log.go | 80 +++++----- backends/rapidpro/schema.sql | 16 +- channel_log.go | 191 +++++++---------------- channel_log_test.go | 49 +++--- handlers/arabiacell/arabiacell_test.go | 4 +- handlers/blackmyna/blackmyna_test.go | 2 +- handlers/burstsms/burstsms_test.go | 4 +- handlers/clickatell/clickatell_test.go | 2 +- handlers/clicksend/clicksend_test.go | 2 +- handlers/dart/dart_test.go | 4 +- handlers/dmark/dmark_test.go | 2 +- handlers/external/external_test.go | 2 +- handlers/facebook/facebook_test.go | 2 +- handlers/facebookapp/facebookapp_test.go | 6 +- handlers/firebase/firebase_test.go | 4 +- handlers/http_test.go | 20 +-- handlers/i2sms/i2sms_test.go | 4 +- handlers/infobip/infobip_test.go | 2 +- handlers/jiochat/jiochat.go | 12 +- handlers/junebug/junebug_test.go | 4 +- handlers/macrokiosk/macrokiosk_test.go | 2 +- handlers/mblox/mblox_test.go | 2 +- handlers/messangi/messangi_test.go | 2 +- handlers/mtarget/mtarget_test.go | 2 +- handlers/nexmo/nexmo_test.go | 4 +- handlers/novo/novo_test.go | 4 +- handlers/plivo/plivo_test.go | 2 +- handlers/slack/slack_test.go | 2 +- handlers/telegram/telegram_test.go | 2 +- handlers/test.go | 2 +- handlers/thinq/thinq_test.go | 2 +- handlers/twiml/twiml_test.go | 32 ++-- handlers/twitter/twitter_test.go | 4 +- handlers/viber/viber_test.go | 6 +- handlers/wechat/wechat.go | 12 +- handlers/whatsapp/whatsapp_test.go | 2 +- handlers/zenvia/zenvia_test.go | 4 +- handlers/zenviaold/zenviaold_test.go | 2 +- sender.go | 2 + server.go | 20 +-- server_test.go | 29 ---- test/status.go | 2 - 44 files changed, 236 insertions(+), 333 deletions(-) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 79d80b564..769dee9fd 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -384,12 +384,11 @@ func (b *backend) WriteChannelLog(ctx context.Context, clog *courier.ChannelLogg timeout, cancel := context.WithTimeout(ctx, backendTimeout) defer cancel() - for _, l := range clog.LegacyLogs() { - err := writeChannelLog(timeout, b, l) - if err != nil { - logrus.WithError(err).Error("error writing channel log") - } + err := writeChannelLog(timeout, b, clog) + if err != nil { + logrus.WithError(err).Error("error writing channel log") } + return nil } diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 2d8927027..a4ccb3d05 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -946,7 +946,7 @@ func (ts *BackendTestSuite) TestChannel() { } func (ts *BackendTestSuite) TestChanneLog() { - knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") + channel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") ctx := context.Background() httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ @@ -961,9 +961,10 @@ func (ts *BackendTestSuite) TestChanneLog() { trace, err := httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) ts.NoError(err) - log := courier.NewLegacyChannelLog("Message Send Error", knChannel, courier.NilMsgID, trace) + clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel) + clog.HTTP(trace) - err = writeChannelLog(ctx, ts.b, log) + err = writeChannelLog(ctx, ts.b, clog) ts.NoError(err) } diff --git a/backends/rapidpro/log.go b/backends/rapidpro/log.go index 16a6aeff9..fe0280759 100644 --- a/backends/rapidpro/log.go +++ b/backends/rapidpro/log.go @@ -2,33 +2,29 @@ package rapidpro import ( "context" - "fmt" + "encoding/json" "time" "github.com/nyaruka/courier" - "github.com/nyaruka/courier/utils" + "github.com/nyaruka/gocommon/jsonx" ) const insertLogSQL = ` -INSERT INTO - channels_channellog("channel_id", "msg_id", "description", "is_error", "method", "url", "request", "response", "response_status", "created_on", "request_time") - VALUES(:channel_id, :msg_id, :description, :is_error, :method, :url, :request, :response, :response_status, :created_on, :request_time) -` +INSERT INTO channels_channellog( log_type, channel_id, msg_id, http_logs, errors, is_error, created_on, elapsed_ms) + VALUES(:log_type, :channel_id, :msg_id, :http_logs, :errors, :is_error, :created_on, :elapsed_ms) + RETURNING id` // ChannelLog is our DB specific struct for logs type ChannelLog struct { - ChannelID courier.ChannelID `db:"channel_id"` - MsgID courier.MsgID `db:"msg_id"` - Description string `db:"description"` - IsError bool `db:"is_error"` - Method string `db:"method"` - URL string `db:"url"` - Request string `db:"request"` - Response string `db:"response"` - ResponseStatus int `db:"response_status"` - CreatedOn time.Time `db:"created_on"` - RequestTime int `db:"request_time"` + Type courier.ChannelLogType `db:"log_type"` + ChannelID courier.ChannelID `db:"channel_id"` + MsgID courier.MsgID `db:"msg_id"` + HTTPLogs json.RawMessage `db:"http_logs"` + Errors json.RawMessage `db:"http_logs"` + IsError bool `db:"is_error"` + CreatedOn time.Time `db:"created_on"` + ElapsedMS int `db:"elapsed_ms"` } // RowID satisfies our batch.Value interface, we are always inserting logs so we have no row id @@ -36,36 +32,40 @@ func (l *ChannelLog) RowID() string { return "" } +type channelError struct { + Message string `json:"message"` + Code string `json:"code"` +} + // WriteChannelLog writes the passed in channel log to the database, we do not queue on errors but instead just throw away the log -func writeChannelLog(ctx context.Context, b *backend, log *courier.ChannelLog) error { - // cast our channel to our own channel type - dbChan, isChan := log.Channel.(*DBChannel) - if !isChan { - return fmt.Errorf("unable to write non-rapidpro channel logs") - } +func writeChannelLog(ctx context.Context, b *backend, clog *courier.ChannelLogger) error { + dbChan := clog.Channel().(*DBChannel) - // if we have an error, append to to our response - if log.Error != "" { - log.Response += "\n\nError: " + log.Error + isError := len(clog.Errors()) > 0 + if !isError { + for _, l := range clog.HTTPLogs() { + if l.StatusCode < 200 || l.StatusCode >= 400 { + isError = true + break + } + } } - // strip null chars from request and response, postgres doesn't like that - log.Request = utils.CleanString(log.Request) - log.Response = utils.CleanString(log.Response) + errors := make([]channelError, 0, len(clog.Errors())) + for i, e := range clog.Errors() { + errors[i] = channelError{Message: e.Message(), Code: e.Code()} + } // create our value for committing v := &ChannelLog{ - ChannelID: dbChan.ID(), - MsgID: log.MsgID, - Description: log.Description, - IsError: log.Error != "", - Method: log.Method, - URL: log.URL, - Request: log.Request, - Response: log.Response, - ResponseStatus: log.StatusCode, - CreatedOn: log.CreatedOn, - RequestTime: int(log.Elapsed / time.Millisecond), + Type: clog.Type(), + ChannelID: dbChan.ID(), + MsgID: clog.MsgID(), + HTTPLogs: jsonx.MustMarshal(clog.HTTPLogs()), + Errors: jsonx.MustMarshal(errors), + IsError: isError, + CreatedOn: clog.CreatedOn(), + ElapsedMS: int(clog.Elapsed() / time.Millisecond), } // queue it diff --git a/backends/rapidpro/schema.sql b/backends/rapidpro/schema.sql index b5861a94b..d137f146a 100644 --- a/backends/rapidpro/schema.sql +++ b/backends/rapidpro/schema.sql @@ -87,18 +87,14 @@ CREATE TABLE msgs_msg ( DROP TABLE IF EXISTS channels_channellog CASCADE; CREATE TABLE channels_channellog ( id serial primary key, - description character varying(255) NOT NULL, + channel_id integer NOT NULL references channels_channel(id) on delete cascade, + msg_id bigint references msgs_msg(id) on delete cascade, + log_type character varying(16), + http_logs jsonb, + errors jsonb, is_error boolean NOT NULL, - url text, - method character varying(16), - request text, - response text, - response_status integer, created_on timestamp with time zone NOT NULL, - request_time integer, - channel_id integer NOT NULL references channels_channel(id) on delete cascade, - msg_id integer references msgs_msg(id) on delete cascade, - session_id integer NULL + elapsed_ms integer ); DROP TABLE IF EXISTS channels_channelevent CASCADE; diff --git a/channel_log.go b/channel_log.go index 23b6de8bd..a7be7e90b 100644 --- a/channel_log.go +++ b/channel_log.go @@ -1,93 +1,12 @@ package courier import ( - "fmt" - "strings" "time" "github.com/nyaruka/gocommon/dates" "github.com/nyaruka/gocommon/httpx" ) -func SanitizeBody(body string) string { - parts := strings.SplitN(body, "\r\n\r\n", 2) - if len(parts) < 2 { - return body - } - - ct := httpx.DetectContentType([]byte(parts[1])) - - // if this isn't text, replace with placeholder - if !strings.HasPrefix(ct, "text") && !strings.HasPrefix(ct, "application/json") { - return fmt.Sprintf("%s\r\n\r\nOmitting non text body of type: %s", parts[0], ct) - } - - return body -} - -// NewLegacyChannelLog creates a new channel log for the passed in channel, id, and http trace -func NewLegacyChannelLog(description string, channel Channel, msgID MsgID, trace *httpx.Trace) *ChannelLog { - log := &ChannelLog{ - Description: description, - Channel: channel, - MsgID: msgID, - Method: trace.Request.Method, - URL: trace.Request.URL.String(), - Request: SanitizeBody(string(trace.RequestTrace)), - CreatedOn: trace.StartTime, - Elapsed: trace.EndTime.Sub(trace.StartTime), - } - - if trace.Response != nil { - log.StatusCode = trace.Response.StatusCode - log.Response = string(trace.SanitizedResponse("...")) - } - - return log -} - -func newLegacyChannelLogFromError(description string, channel Channel, msgID MsgID, elapsed time.Duration, err error) *ChannelLog { - return &ChannelLog{ - Description: description, - Channel: channel, - MsgID: msgID, - Error: err.Error(), - CreatedOn: time.Now(), - Elapsed: elapsed, - } -} - -// WithError augments the passed in ChannelLog with the passed in description and error if error is not nil -func (l *ChannelLog) WithError(description string, err error) *ChannelLog { - if err != nil { - l.Error = err.Error() - l.Description = description - } - - return l -} - -func (l *ChannelLog) String() string { - return fmt.Sprintf("%s: %d %s %d\n%s\n%s\n%s", l.Description, l.StatusCode, l.URL, l.Elapsed, l.Error, l.Request, l.Response) -} - -// ChannelLog represents the log for a msg being received, sent or having its status updated. It includes the HTTP request -// and response for the action as well as the channel it was performed on and an option ID of the msg (for some error -// cases we may log without a msg id) -type ChannelLog struct { - Description string - Channel Channel - MsgID MsgID - Method string - URL string - StatusCode int - Error string - Request string - Response string - Elapsed time.Duration - CreatedOn time.Time -} - // ChannelLogType is the type of channel interaction we are logging type ChannelLogType string @@ -100,26 +19,36 @@ const ( ChannelLogTypeTokenFetch ChannelLogType = "token_fetch" ) -var logTypeDescriptions = map[ChannelLogType]string{ - ChannelLogTypeUnknown: "Other Event", - ChannelLogTypeMsgSend: "Message Send", - ChannelLogTypeMsgStatus: "Message Status", - ChannelLogTypeMsgReceive: "Message Receive", - ChannelLogTypeEventReceive: "Event Receive", - ChannelLogTypeTokenFetch: "Token Fetch", +type ChannelError struct { + message string + code string } -type ChannelLogger struct { - type_ ChannelLogType - channel Channel - msgID MsgID +func NewChannelError(message, code string) ChannelError { + return ChannelError{message: message, code: code} +} + +func (e *ChannelError) Message() string { + return e.message +} - traces []*httpx.Trace - errors []string +func (e *ChannelError) Code() string { + return e.code +} + +type ChannelLogger struct { + type_ ChannelLogType + channel Channel + msgID MsgID + recorder *httpx.Recorder + httpLogs []*httpx.Log + errors []ChannelError createdOn time.Time + elapsed time.Duration +} - // deprecated - logs []*ChannelLog +func NewChannelLogForIncoming(r *httpx.Recorder, channel Channel) *ChannelLogger { + return &ChannelLogger{type_: ChannelLogTypeUnknown, recorder: r, channel: channel, createdOn: dates.Now()} } func NewChannelLogForSend(msg Msg) *ChannelLogger { @@ -130,62 +59,60 @@ func NewChannelLog(t ChannelLogType, channel Channel) *ChannelLogger { return &ChannelLogger{type_: t, channel: channel, createdOn: dates.Now()} } -func (l *ChannelLogger) SetType(t ChannelLogType) { - l.type_ = t +// HTTP logs an outgoing HTTP request and response +func (l *ChannelLogger) HTTP(t *httpx.Trace) { + l.httpLogs = append(l.httpLogs, l.traceToLog(t)) } -func (l *ChannelLogger) SetMsgID(id MsgID) { - l.msgID = id +func (l *ChannelLogger) Error(err error) { + l.errors = append(l.errors, NewChannelError(err.Error(), "")) } -// Recorder logs a recording of an incoming HTTP request -func (l *ChannelLogger) Recorder(r *httpx.Recorder) { - // prepend so it's the first HTTP request in the log - l.traces = append([]*httpx.Trace{r.Trace}, l.traces...) - - if l.channel != nil { - l.logs = append(l.logs, NewLegacyChannelLog(logTypeDescriptions[l.type_], l.channel, l.msgID, r.Trace)) +func (l *ChannelLogger) End() { + if l.recorder != nil { + // prepend so it's the first HTTP request in the log + l.httpLogs = append([]*httpx.Log{l.traceToLog(l.recorder.Trace)}, l.httpLogs...) } + + l.elapsed = time.Since(l.createdOn) } -// HTTP logs an outgoing HTTP request and response -func (l *ChannelLogger) HTTP(t *httpx.Trace) { - l.traces = append(l.traces, t) +func (l *ChannelLogger) Type() ChannelLogType { + return l.type_ +} - if l.channel != nil { - l.logs = append(l.logs, NewLegacyChannelLog(logTypeDescriptions[l.type_], l.channel, l.msgID, t)) - } +func (l *ChannelLogger) SetType(t ChannelLogType) { + l.type_ = t } -func (l *ChannelLogger) Error(err error) { - l.errors = append(l.errors, err.Error()) - - if l.channel != nil { - // if we have an existing log which isn't already an error, update it - if len(l.logs) > 0 && l.logs[len(l.logs)-1].Error == "" { - l.logs[len(l.logs)-1].Error = err.Error() - } else { - l.logs = append(l.logs, newLegacyChannelLogFromError(logTypeDescriptions[l.type_], l.channel, l.msgID, 0, err)) - } - } +func (l *ChannelLogger) Channel() Channel { + return l.channel } -func (l *ChannelLogger) Type() ChannelLogType { - return l.type_ +func (l *ChannelLogger) MsgID() MsgID { + return l.msgID } -func (l *ChannelLogger) Traces() []*httpx.Trace { - return l.traces +func (l *ChannelLogger) SetMsgID(id MsgID) { + l.msgID = id } -func (l *ChannelLogger) Errors() []string { - return l.errors +func (l *ChannelLogger) HTTPLogs() []*httpx.Log { + return l.httpLogs } -func (l *ChannelLogger) LegacyLogs() []*ChannelLog { - return l.logs +func (l *ChannelLogger) Errors() []ChannelError { + return l.errors } func (l *ChannelLogger) CreatedOn() time.Time { return l.createdOn } + +func (l *ChannelLogger) Elapsed() time.Duration { + return l.elapsed +} + +func (l *ChannelLogger) traceToLog(t *httpx.Trace) *httpx.Log { + return httpx.NewLog(t, 2048, 50000, nil) +} diff --git a/channel_log_test.go b/channel_log_test.go index 8df4f204d..c7e4bf801 100644 --- a/channel_log_test.go +++ b/channel_log_test.go @@ -1,8 +1,10 @@ package courier_test import ( + "errors" "net/http" "testing" + "time" "github.com/nyaruka/courier" "github.com/nyaruka/courier/test" @@ -10,7 +12,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestNewChannelLogFromTrace(t *testing.T) { +func TestChannelLog(t *testing.T) { httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ "https://api.messages.com/send.json": { httpx.NewMockResponse(200, nil, []byte(`{"status":"success"}`)), @@ -20,35 +22,42 @@ func TestNewChannelLogFromTrace(t *testing.T) { defer httpx.SetRequestor(httpx.DefaultRequestor) channel := test.NewMockChannel("fef91e9b-a6ed-44fb-b6ce-feed8af585a8", "NX", "1234", "US", nil) + clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel) // make a request that will have a response req, _ := http.NewRequest("POST", "https://api.messages.com/send.json", nil) trace, err := httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) assert.NoError(t, err) - log := courier.NewLegacyChannelLog("Send message", channel, courier.NewMsgID(1234), trace) - - assert.Equal(t, "Send message", log.Description) - assert.Equal(t, channel, log.Channel) - assert.Equal(t, courier.NewMsgID(1234), log.MsgID) - assert.Equal(t, "POST", log.Method) - assert.Equal(t, "https://api.messages.com/send.json", log.URL) - assert.Equal(t, 200, log.StatusCode) - assert.Equal(t, "", log.Error) - assert.Equal(t, "POST /send.json HTTP/1.1\r\nHost: api.messages.com\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 0\r\nAccept-Encoding: gzip\r\n\r\n", log.Request) - assert.Equal(t, "HTTP/1.0 200 OK\r\nContent-Length: 20\r\n\r\n{\"status\":\"success\"}", log.Response) - assert.Equal(t, trace.StartTime, log.CreatedOn) - assert.Equal(t, trace.EndTime.Sub(trace.StartTime), log.Elapsed) + clog.HTTP(trace) // make a request that has no response (connection error) req, _ = http.NewRequest("POST", "https://api.messages.com/send.json", nil) trace, err = httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) assert.EqualError(t, err, "unable to connect to server") - log = courier.NewLegacyChannelLog("Send message", channel, courier.NewMsgID(1234), trace) - - assert.Equal(t, 0, log.StatusCode) - assert.Equal(t, "", log.Error) - assert.Equal(t, "POST /send.json HTTP/1.1\r\nHost: api.messages.com\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 0\r\nAccept-Encoding: gzip\r\n\r\n", log.Request) - assert.Equal(t, "", log.Response) + clog.HTTP(trace) + clog.Error(errors.New("this is an error")) + clog.End() + + assert.Equal(t, courier.ChannelLogTypeTokenFetch, clog.Type()) + assert.Equal(t, channel, clog.Channel()) + assert.Equal(t, 2, len(clog.HTTPLogs())) + assert.Equal(t, 1, len(clog.Errors())) + assert.Greater(t, clog.Elapsed(), time.Duration(0)) + + hlog1 := clog.HTTPLogs()[0] + assert.Equal(t, "https://api.messages.com/send.json", hlog1.URL) + assert.Equal(t, 200, hlog1.StatusCode) + assert.Equal(t, "POST /send.json HTTP/1.1\r\nHost: api.messages.com\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 0\r\nAccept-Encoding: gzip\r\n\r\n", hlog1.Request) + assert.Equal(t, "HTTP/1.0 200 OK\r\nContent-Length: 20\r\n\r\n{\"status\":\"success\"}", hlog1.Response) + + hlog2 := clog.HTTPLogs()[1] + assert.Equal(t, 0, hlog2.StatusCode) + assert.Equal(t, "POST /send.json HTTP/1.1\r\nHost: api.messages.com\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 0\r\nAccept-Encoding: gzip\r\n\r\n", hlog2.Request) + assert.Equal(t, "", hlog2.Response) + + err1 := clog.Errors()[0] + assert.Equal(t, "this is an error", err1.Message()) + assert.Equal(t, "", err1.Code()) } diff --git a/handlers/arabiacell/arabiacell_test.go b/handlers/arabiacell/arabiacell_test.go index 3400cac75..001aba3b2 100644 --- a/handlers/arabiacell/arabiacell_test.go +++ b/handlers/arabiacell/arabiacell_test.go @@ -70,7 +70,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `not xml`, MockResponseStatus: 200, ExpectedStatus: "E", - ExpectedErrors: []string{"EOF"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("EOF", "")}, SendPrep: setSendURL, }, { @@ -80,7 +80,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `501failure`, MockResponseStatus: 200, ExpectedStatus: "F", - ExpectedErrors: []string{"Received invalid response code: 501"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid response code: 501", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/blackmyna/blackmyna_test.go b/handlers/blackmyna/blackmyna_test.go index 1370c781a..7f9d199ce 100644 --- a/handlers/blackmyna/blackmyna_test.go +++ b/handlers/blackmyna/blackmyna_test.go @@ -94,7 +94,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 200, - ExpectedErrors: []string{"no external id returned in body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("no external id returned in body", "")}, ExpectedPostParams: map[string]string{"message": `No External ID`, "address": "+250788383383", "senderaddress": "2020"}, ExpectedStatus: "E", SendPrep: setSendURL, diff --git a/handlers/burstsms/burstsms_test.go b/handlers/burstsms/burstsms_test.go index 1e2f89d27..4144a788b 100644 --- a/handlers/burstsms/burstsms_test.go +++ b/handlers/burstsms/burstsms_test.go @@ -71,7 +71,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `not json`, MockResponseStatus: 200, ExpectedStatus: "E", - ExpectedErrors: []string{"invalid character 'o' in literal null (expecting 'u')"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("invalid character 'o' in literal null (expecting 'u')", "")}, SendPrep: setSendURL, }, { @@ -81,7 +81,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "message_id": 0 }`, MockResponseStatus: 200, ExpectedStatus: "F", - ExpectedErrors: []string{"Received invalid message id: 0"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid message id: 0", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/clickatell/clickatell_test.go b/handlers/clickatell/clickatell_test.go index b113e7ee2..2489e44d7 100644 --- a/handlers/clickatell/clickatell_test.go +++ b/handlers/clickatell/clickatell_test.go @@ -71,7 +71,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"content": "Error Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, ExpectedStatus: "E", - ExpectedErrors: []string{"Key path not found"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Key path not found", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/clicksend/clicksend_test.go b/handlers/clicksend/clicksend_test.go index 90d5f011d..a566e27ec 100644 --- a/handlers/clicksend/clicksend_test.go +++ b/handlers/clicksend/clicksend_test.go @@ -147,7 +147,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: failureResponse, MockResponseStatus: 200, ExpectedStatus: "E", - ExpectedErrors: []string{"received non SUCCESS status: FAILURE"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received non SUCCESS status: FAILURE", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/dart/dart_test.go b/handlers/dart/dart_test.go index 33a2d5713..f83a49b66 100644 --- a/handlers/dart/dart_test.go +++ b/handlers/dart/dart_test.go @@ -106,7 +106,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, ExpectedStatus: "E", - ExpectedErrors: []string{"Error 001: Authentication Error"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Error 001: Authentication Error", "")}, SendPrep: setSendURL, }, { @@ -117,7 +117,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, ExpectedStatus: "E", - ExpectedErrors: []string{"Error 101: Account expired or invalid parameters"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Error 101: Account expired or invalid parameters", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/dmark/dmark_test.go b/handlers/dmark/dmark_test.go index 015ef5b1b..23affbf45 100644 --- a/handlers/dmark/dmark_test.go +++ b/handlers/dmark/dmark_test.go @@ -79,7 +79,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedHeaders: map[string]string{"Authorization": "Token Authy"}, ExpectedPostParams: map[string]string{"text": "Error Message", "receiver": "250788383383", "sender": "2020"}, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get sms_id from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sms_id from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/external/external_test.go b/handlers/external/external_test.go index d786508a8..e1b8d3b83 100644 --- a/handlers/external/external_test.go +++ b/handlers/external/external_test.go @@ -471,7 +471,7 @@ var xmlSendWithResponseContentTestCases = []ChannelSendTestCase{ ExpectedRequestBody: `+250788383383Error Message2020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, ExpectedStatus: "E", - ExpectedErrors: []string{"Received invalid response content: 1"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid response content: 1", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index 3761a8267..09814f324 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -670,7 +670,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get message_id from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index ab151d52c..2613d9be3 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -491,7 +491,7 @@ var SendTestCasesFBA = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get message_id from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, SendPrep: setSendURL, }, { @@ -604,7 +604,7 @@ var SendTestCasesIG = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get message_id from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, SendPrep: setSendURL, }, { @@ -756,7 +756,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MsgText: "templated message", MsgURN: "whatsapp:250788123123", MsgMetadata: json.RawMessage(`{"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}}`), - ExpectedErrors: []string{`unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError(`unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, "")}, }, { Label: "Interactive Button Message Send", diff --git a/handlers/firebase/firebase_test.go b/handlers/firebase/firebase_test.go index 2e25898e1..0a95c7a4b 100644 --- a/handlers/firebase/firebase_test.go +++ b/handlers/firebase/firebase_test.go @@ -138,7 +138,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "success": 0 }`, MockResponseStatus: 200, ExpectedStatus: "E", - ExpectedErrors: []string{"received non-1 value for success in response"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received non-1 value for success in response", "")}, SendPrep: setSendURL, }, { @@ -149,7 +149,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "success": 1 }`, MockResponseStatus: 200, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get multicast_id from response"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get multicast_id from response", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/http_test.go b/handlers/http_test.go index 85e2702af..4e24550b0 100644 --- a/handlers/http_test.go +++ b/handlers/http_test.go @@ -31,25 +31,21 @@ func TestDoHTTPRequest(t *testing.T) { assert.NoError(t, err) assert.Equal(t, 200, resp.StatusCode) assert.Equal(t, []byte(`{"status":"success"}`), respBody) - assert.Len(t, clog.LegacyLogs(), 1) + assert.Len(t, clog.HTTPLogs(), 1) - log1 := clog.LegacyLogs()[0] - assert.Equal(t, 200, log1.StatusCode) - assert.Equal(t, mc, log1.Channel) - assert.Equal(t, courier.NewMsgID(123), log1.MsgID) - assert.Equal(t, "https://api.messages.com/send.json", log1.URL) + hlog1 := clog.HTTPLogs()[0] + assert.Equal(t, 200, hlog1.StatusCode) + assert.Equal(t, "https://api.messages.com/send.json", hlog1.URL) req, _ = http.NewRequest("POST", "https://api.messages.com/send.json", nil) resp, _, err = handlers.RequestHTTP(req, clog) assert.NoError(t, err) assert.Equal(t, 400, resp.StatusCode) - assert.Len(t, clog.LegacyLogs(), 2) + assert.Len(t, clog.HTTPLogs(), 2) - log2 := clog.LegacyLogs()[1] - assert.Equal(t, 400, log2.StatusCode) - assert.Equal(t, mc, log2.Channel) - assert.Equal(t, courier.NewMsgID(123), log2.MsgID) - assert.Equal(t, "https://api.messages.com/send.json", log2.URL) + hlog2 := clog.HTTPLogs()[1] + assert.Equal(t, 400, hlog2.StatusCode) + assert.Equal(t, "https://api.messages.com/send.json", hlog2.URL) } func TestMakeHTTPRequest(t *testing.T) { diff --git a/handlers/i2sms/i2sms_test.go b/handlers/i2sms/i2sms_test.go index b733dd593..86345e572 100644 --- a/handlers/i2sms/i2sms_test.go +++ b/handlers/i2sms/i2sms_test.go @@ -63,7 +63,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `not json`, MockResponseStatus: 200, ExpectedStatus: "E", - ExpectedErrors: []string{"invalid character 'o' in literal null (expecting 'u')"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("invalid character 'o' in literal null (expecting 'u')", "")}, SendPrep: setSendURL, }, { @@ -73,7 +73,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"result":{}, "error_code": "10", "error_desc": "Failed"}`, MockResponseStatus: 200, ExpectedStatus: "F", - ExpectedErrors: []string{"Received invalid response code: 10"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid response code: 10", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/infobip/infobip_test.go b/handlers/infobip/infobip_test.go index 482ad992b..f35864685 100644 --- a/handlers/infobip/infobip_test.go +++ b/handlers/infobip/infobip_test.go @@ -295,7 +295,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Simple Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, ExpectedStatus: "E", - ExpectedErrors: []string{"received error status: '2'"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error status: '2'", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 055b17fa7..fe72ba914 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -168,7 +168,7 @@ type fetchPayload struct { // fetchAccessToken tries to fetch a new token for our channel, setting the result in redis func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) error { - logger := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel) tokenURL, _ := url.Parse(fmt.Sprintf("%s/%s", sendURL, "auth/token.action")) payload := &fetchPayload{ @@ -184,15 +184,17 @@ func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { - return h.Backend().WriteChannelLog(ctx, logger) + clog.End() + return h.Backend().WriteChannelLog(ctx, clog) } accessToken, err := jsonparser.GetString(respBody, "access_token") if err != nil { - logger.Error(errors.New("access_token not found in response")) - return h.Backend().WriteChannelLog(ctx, logger) + clog.Error(errors.New("access_token not found in response")) + clog.End() + return h.Backend().WriteChannelLog(ctx, clog) } rc := h.Backend().RedisPool().Get() diff --git a/handlers/junebug/junebug_test.go b/handlers/junebug/junebug_test.go index 3b3b913d9..b40d8e73b 100644 --- a/handlers/junebug/junebug_test.go +++ b/handlers/junebug/junebug_test.go @@ -178,7 +178,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, MockResponseBody: "not json", ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get result.message_id from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get result.message_id from body", "")}, SendPrep: setSendURL, }, { @@ -188,7 +188,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, MockResponseBody: "{}", ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get result.message_id from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get result.message_id from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/macrokiosk/macrokiosk_test.go b/handlers/macrokiosk/macrokiosk_test.go index 06ada1b68..dcf1af5b1 100644 --- a/handlers/macrokiosk/macrokiosk_test.go +++ b/handlers/macrokiosk/macrokiosk_test.go @@ -110,7 +110,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, - ExpectedErrors: []string{"unable to parse response body from Macrokiosk"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to parse response body from Macrokiosk", "")}, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", diff --git a/handlers/mblox/mblox_test.go b/handlers/mblox/mblox_test.go index d6584a41e..ecec6f604 100644 --- a/handlers/mblox/mblox_test.go +++ b/handlers/mblox/mblox_test.go @@ -137,7 +137,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, - ExpectedErrors: []string{"unable to parse response body from MBlox"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to parse response body from MBlox", "")}, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", diff --git a/handlers/messangi/messangi_test.go b/handlers/messangi/messangi_test.go index 8172e2d7c..4a8750770 100644 --- a/handlers/messangi/messangi_test.go +++ b/handlers/messangi/messangi_test.go @@ -83,7 +83,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `sendMTERRORCompleted`, MockResponseStatus: 200, ExpectedStatus: "F", - ExpectedErrors: []string{"Received invalid response description: Completed"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid response description: Completed", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/mtarget/mtarget_test.go b/handlers/mtarget/mtarget_test.go index 3a1169ddd..73ffac3ef 100644 --- a/handlers/mtarget/mtarget_test.go +++ b/handlers/mtarget/mtarget_test.go @@ -118,7 +118,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"results":[{"code": "3", "ticket": "null"}]}`, MockResponseStatus: 200, ExpectedStatus: "F", - ExpectedErrors: []string{"Error status code, failing permanently"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Error status code, failing permanently", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/nexmo/nexmo_test.go b/handlers/nexmo/nexmo_test.go index 590662af5..f4856a4f1 100644 --- a/handlers/nexmo/nexmo_test.go +++ b/handlers/nexmo/nexmo_test.go @@ -113,7 +113,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Error status", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, ExpectedStatus: "E", - ExpectedErrors: []string{"failed to send message, received error status [10]"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("failed to send message, received error status [10]", "")}, SendPrep: setSendURL, }, { @@ -144,7 +144,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, ExpectedStatus: "E", - ExpectedErrors: []string{"failed to send message, received error status [1]"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("failed to send message, received error status [1]", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/novo/novo_test.go b/handlers/novo/novo_test.go index 9349fecaa..c87db82f0 100644 --- a/handlers/novo/novo_test.go +++ b/handlers/novo/novo_test.go @@ -84,7 +84,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"error": "Incorrect Query String Authentication ","expectedQueryString": "8868;18686846480;test;"}`, MockResponseStatus: 200, ExpectedStatus: "F", - ExpectedErrors: []string{"received invalid response"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received invalid response", "")}, SendPrep: setSendURL, }, { @@ -94,7 +94,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"error": "Incorrect Query String Authentication ","expectedQueryString": "8868;18686846480;test;"}`, MockResponseStatus: 200, ExpectedStatus: "F", - ExpectedErrors: []string{"received invalid response"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received invalid response", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/plivo/plivo_test.go b/handlers/plivo/plivo_test.go index bcc39139f..0729eb64c 100644 --- a/handlers/plivo/plivo_test.go +++ b/handlers/plivo/plivo_test.go @@ -104,7 +104,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, - ExpectedErrors: []string{"unable to parse response body from Plivo"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to parse response body from Plivo", "")}, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 0cf81b90c..6aa006df1 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -206,7 +206,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{"channel":"U0123ABCDEF","text":"Hello"}`, ExpectedStatus: "E", - ExpectedErrors: []string{"invalid_auth"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("invalid_auth", "")}, SendPrep: setSendUrl, }, } diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index 2b2244e39..de54e727c 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -712,7 +712,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "telegram:12345", MsgAttachments: []string{"unknown/foo:https://foo.bar/unknown.foo"}, ExpectedStatus: "E", - ExpectedErrors: []string{"unknown attachment content type: unknown/foo"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unknown attachment content type: unknown/foo", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/test.go b/handlers/test.go index b7c4988c1..7a90f4c9e 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -102,7 +102,7 @@ type ChannelSendTestCase struct { ExpectedStatus string ExpectedExternalID string - ExpectedErrors []string + ExpectedErrors []courier.ChannelError ExpectedStopEvent bool ExpectedContactURNs map[string]bool diff --git a/handlers/thinq/thinq_test.go b/handlers/thinq/thinq_test.go index 420ef516f..ea5fdf923 100644 --- a/handlers/thinq/thinq_test.go +++ b/handlers/thinq/thinq_test.go @@ -93,7 +93,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"No External ID"}`, ExpectedStatus: "E", - ExpectedErrors: []string{"Unable to read external ID from guid field"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Unable to read external ID from guid field", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index 1ad905905..d0089d9ff 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -325,7 +325,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get sid from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -336,7 +336,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get sid from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -348,7 +348,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStopEvent: true, ExpectedStatus: "F", - ExpectedErrors: []string{"received error code from twilio '21610'"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, SendPrep: setSendURL, }, { @@ -359,7 +359,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get sid from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -410,7 +410,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get sid from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -421,7 +421,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get sid from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -433,7 +433,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedStopEvent: true, ExpectedStatus: "F", - ExpectedErrors: []string{"received error code from twilio '21610'"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, SendPrep: setSendURL, }, { @@ -444,7 +444,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get sid from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -495,7 +495,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get sid from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -506,7 +506,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get sid from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -518,7 +518,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "F", ExpectedStopEvent: true, - ExpectedErrors: []string{"received error code from twilio '21610'"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, SendPrep: setSendURL, }, { @@ -529,7 +529,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get sid from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -580,7 +580,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get sid from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -591,7 +591,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get sid from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -603,7 +603,7 @@ var swSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "F", ExpectedStopEvent: true, - ExpectedErrors: []string{"received error code from twilio '21610'"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, SendPrep: setSendURL, }, { @@ -614,7 +614,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get sid from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/twitter/twitter_test.go b/handlers/twitter/twitter_test.go index eda1ea3b4..5c0edd989 100644 --- a/handlers/twitter/twitter_test.go +++ b/handlers/twitter/twitter_test.go @@ -346,7 +346,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, ExpectedStatus: "W", ExpectedExternalID: "133", - ExpectedErrors: []string{"unable to upload media, unsupported Twitter attachment"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to upload media, unsupported Twitter attachment", "")}, SendPrep: setSendURL, }, { @@ -356,7 +356,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get message_id from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index 4a260ff3a..821c1b917 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -146,7 +146,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, ExpectedStatus: "E", - ExpectedErrors: []string{"received non-0 status: '3'"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received non-0 status: '3'", "")}, SendPrep: setSendURL, }, { @@ -158,7 +158,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, ExpectedStatus: "E", - ExpectedErrors: []string{"received invalid JSON response"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received invalid JSON response", "")}, SendPrep: setSendURL, }, { @@ -177,7 +177,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ var invalidTokenSendTestCases = []ChannelSendTestCase{ { Label: "Invalid token", - ExpectedErrors: []string{"missing auth token in config"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("missing auth token in config", "")}, }, } diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index 3d56dd3f7..ff6f8b47e 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -97,7 +97,7 @@ func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http // fetchAccessToken tries to fetch a new token for our channel, setting the result in redis func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) error { - logger := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel) form := url.Values{ "grant_type": []string{"client_credential"}, @@ -111,15 +111,17 @@ func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, logger) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { - return h.Backend().WriteChannelLog(ctx, logger) + clog.End() + return h.Backend().WriteChannelLog(ctx, clog) } accessToken, err := jsonparser.GetString(respBody, "access_token") if err != nil { - logger.Error(errors.New("access_token not found in response")) - return h.Backend().WriteChannelLog(ctx, logger) + clog.Error(errors.New("access_token not found in response")) + clog.End() + return h.Backend().WriteChannelLog(ctx, clog) } expiration, err := jsonparser.GetInt(respBody, "expires_in") diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index 6523e70ed..1762dbbca 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -577,7 +577,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Label: "Template Invalid Language", MsgText: "templated message", MsgURN: "whatsapp:250788123123", - ExpectedErrors: []string{`unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError(`unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, "")}, MsgMetadata: json.RawMessage(`{"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}}`), }, { diff --git a/handlers/zenvia/zenvia_test.go b/handlers/zenvia/zenvia_test.go index 6c910a011..41abb6222 100644 --- a/handlers/zenvia/zenvia_test.go +++ b/handlers/zenvia/zenvia_test.go @@ -316,7 +316,7 @@ var defaultWhatsappSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"No External ID"}]}`, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get id from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get id from body", "")}, SendPrep: setSendURL, }, { @@ -392,7 +392,7 @@ var defaultSMSSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"No External ID"}]}`, ExpectedStatus: "E", - ExpectedErrors: []string{"unable to get id from body"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get id from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/zenviaold/zenviaold_test.go b/handlers/zenviaold/zenviaold_test.go index cd56ee90f..47eb9b3a1 100644 --- a/handlers/zenviaold/zenviaold_test.go +++ b/handlers/zenviaold/zenviaold_test.go @@ -198,7 +198,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"No External ID","callbackOption":"FINAL","id":"10","aggregateId":""}}`, ExpectedStatus: "E", - ExpectedErrors: []string{"received non-success response: '05'"}, + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received non-success response: '05'", "")}, SendPrep: setSendURL}, { Label: "Error Sending", diff --git a/sender.go b/sender.go index 1f5c1b0e2..4cf2a1a96 100644 --- a/sender.go +++ b/sender.go @@ -230,6 +230,8 @@ func (w *Sender) sendMessage(msg Msg) { log.WithError(err).Info("error writing msg status") } + clog.End() + // write our logs as well err = backend.WriteChannelLog(writeCTX, clog) if err != nil { diff --git a/server.go b/server.go index 047c1c0e2..67bf784de 100644 --- a/server.go +++ b/server.go @@ -298,9 +298,9 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe } }() - logger := NewChannelLog(ChannelLogTypeUnknown, channel) + clog := NewChannelLogForIncoming(recorder, channel) - events, hErr := handlerFunc(ctx, channel, recorder.ResponseWriter, r, logger) + events, hErr := handlerFunc(ctx, channel, recorder.ResponseWriter, r, clog) duration := time.Since(start) secondDuration := float64(duration) / float64(time.Second) @@ -316,8 +316,6 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe writeAndLogRequestError(ctx, w, r, channel, err) } - logger.Recorder(recorder) - if channel != nil { // if we have a channel but no events were created, we still log this to analytics if len(events) == 0 { @@ -331,23 +329,25 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe for _, event := range events { switch e := event.(type) { case Msg: - logger.SetMsgID(e.ID()) - logger.SetType(ChannelLogTypeMsgReceive) + clog.SetMsgID(e.ID()) + clog.SetType(ChannelLogTypeMsgReceive) analytics.Gauge(fmt.Sprintf("courier.msg_receive_%s", channel.ChannelType()), secondDuration) LogMsgReceived(r, e) case MsgStatus: - logger.SetMsgID(e.ID()) - logger.SetType(ChannelLogTypeMsgStatus) + clog.SetMsgID(e.ID()) + clog.SetType(ChannelLogTypeMsgStatus) analytics.Gauge(fmt.Sprintf("courier.msg_status_%s", channel.ChannelType()), secondDuration) LogMsgStatusReceived(r, e) case ChannelEvent: - logger.SetType(ChannelLogTypeEventReceive) + clog.SetType(ChannelLogTypeEventReceive) analytics.Gauge(fmt.Sprintf("courier.evt_receive_%s", channel.ChannelType()), secondDuration) LogChannelEventReceived(r, e) } } - if err := s.backend.WriteChannelLog(ctx, logger); err != nil { + clog.End() + + if err := s.backend.WriteChannelLog(ctx, clog); err != nil { logrus.WithError(err).Error("error writing channel log") } } diff --git a/server_test.go b/server_test.go index ffe315ef5..41ad3083a 100644 --- a/server_test.go +++ b/server_test.go @@ -56,32 +56,3 @@ func TestServer(t *testing.T) { assert.NoError(t, err) assert.Contains(t, string(trace.ResponseBody), "method not allowed") } - -func TestSanitizeBody(t *testing.T) { - tcs := []struct { - Label string - Body string - Result string - }{ - { - "empty", - "", - "", - }, - { - "valid", - "POST /v1/messages HTTP/1.1\r\nContent-Length: 125\r\n\r\nBody", - "POST /v1/messages HTTP/1.1\r\nContent-Length: 125\r\n\r\nBody", - }, - { - "application/octet-stream", - "POST /v1/messages HTTP/1.1\r\nContent-Length: 125\r\n\r\nJFIF``C", - "POST /v1/messages HTTP/1.1\r\nContent-Length: 125\r\n\r\nOmitting non text body of type: application/octet-stream", - }, - } - - for _, tc := range tcs { - result := courier.SanitizeBody(tc.Body) - assert.Equal(t, tc.Result, result, "%s: unexpected result", tc.Label) - } -} diff --git a/test/status.go b/test/status.go index b601fda81..01fca36f2 100644 --- a/test/status.go +++ b/test/status.go @@ -15,8 +15,6 @@ type mockMsgStatus struct { externalID string status courier.MsgStatusValue createdOn time.Time - - logs []*courier.ChannelLog } func (m *mockMsgStatus) ChannelUUID() courier.ChannelUUID { return m.channel.UUID() } From 47868d9834c2158e0295f775622e7d5c82e1b471 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 24 Aug 2022 14:29:25 -0500 Subject: [PATCH 096/294] Rename ChannelLogger to ChannelLog --- backend.go | 2 +- backends/rapidpro/backend.go | 2 +- backends/rapidpro/log.go | 2 +- channel_log.go | 40 +++++++++++------------ handler.go | 6 ++-- handler_test.go | 4 +-- handlers/africastalking/africastalking.go | 6 ++-- handlers/arabiacell/arabiacell.go | 2 +- handlers/blackmyna/blackmyna.go | 6 ++-- handlers/bongolive/bongolive.go | 4 +-- handlers/burstsms/burstsms.go | 2 +- handlers/chikka/chikka.go | 4 +-- handlers/clickatell/clickatell.go | 6 ++-- handlers/clickmobile/clickmobile.go | 4 +-- handlers/clicksend/clicksend.go | 2 +- handlers/dart/dart.go | 6 ++-- handlers/discord/discord.go | 8 ++--- handlers/dmark/dmark.go | 6 ++-- handlers/external/external.go | 10 +++--- handlers/facebook/facebook.go | 8 ++--- handlers/facebook/facebook_test.go | 4 +-- handlers/facebookapp/facebookapp.go | 12 +++---- handlers/facebookapp/facebookapp_test.go | 12 +++---- handlers/firebase/firebase.go | 6 ++-- handlers/freshchat/freshchat.go | 4 +-- handlers/generic.go | 4 +-- handlers/globe/globe.go | 4 +-- handlers/highconnection/highconnection.go | 6 ++-- handlers/hormuud/hormuud.go | 6 ++-- handlers/http.go | 6 ++-- handlers/i2sms/i2sms.go | 4 +-- handlers/infobip/infobip.go | 6 ++-- handlers/jasmin/jasmin.go | 6 ++-- handlers/jiochat/jiochat.go | 8 ++--- handlers/jiochat/jiochat_test.go | 4 +-- handlers/junebug/junebug.go | 6 ++-- handlers/kaleyra/kaleyra.go | 6 ++-- handlers/kannel/kannel.go | 6 ++-- handlers/line/line.go | 4 +-- handlers/m3tech/m3tech.go | 4 +-- handlers/macrokiosk/macrokiosk.go | 6 ++-- handlers/mblox/mblox.go | 4 +-- handlers/messangi/messangi.go | 2 +- handlers/mtarget/mtarget.go | 4 +-- handlers/nexmo/nexmo.go | 6 ++-- handlers/novo/novo.go | 4 +-- handlers/playmobile/playmobile.go | 4 +-- handlers/plivo/plivo.go | 6 ++-- handlers/redrabbit/redrabbit.go | 2 +- handlers/rocketchat/rocketchat.go | 4 +-- handlers/shaqodoon/shaqodoon.go | 4 +-- handlers/slack/slack.go | 14 ++++---- handlers/slack/slack_test.go | 4 +-- handlers/smscentral/smscentral.go | 4 +-- handlers/start/start.go | 4 +-- handlers/telegram/telegram.go | 8 ++--- handlers/telesom/telesom.go | 4 +-- handlers/thinq/thinq.go | 6 ++-- handlers/twiml/twiml.go | 6 ++-- handlers/twitter/twitter.go | 8 ++--- handlers/viber/viber.go | 4 +-- handlers/vk/vk.go | 8 ++--- handlers/vk/vk_test.go | 4 +-- handlers/wavy/wavy.go | 8 ++--- handlers/wechat/wechat.go | 8 ++--- handlers/wechat/wechat_test.go | 4 +-- handlers/whatsapp/whatsapp.go | 12 +++---- handlers/yo/yo.go | 4 +-- handlers/zenvia/zenvia.go | 6 ++-- handlers/zenviaold/zenviaold.go | 6 ++-- server.go | 4 +-- test/backend.go | 12 +++---- 72 files changed, 216 insertions(+), 216 deletions(-) diff --git a/backend.go b/backend.go index 32ba7fbd5..7679fde04 100644 --- a/backend.go +++ b/backend.go @@ -63,7 +63,7 @@ type Backend interface { WriteChannelEvent(context.Context, ChannelEvent) error // WriteChannelLog writes the passed in channel log to our backend - WriteChannelLog(context.Context, *ChannelLogger) error + WriteChannelLog(context.Context, *ChannelLog) error // PopNextOutgoingMsg returns the next message that needs to be sent, callers should call MarkOutgoingMsgComplete with the // returned message when they have dealt with the message (regardless of whether it was sent or not) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 769dee9fd..7aa330df4 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -380,7 +380,7 @@ func (b *backend) WriteChannelEvent(ctx context.Context, event courier.ChannelEv } // WriteChannelLog persists the passed in log to our database, for rapidpro we swallow all errors, logging isn't critical -func (b *backend) WriteChannelLog(ctx context.Context, clog *courier.ChannelLogger) error { +func (b *backend) WriteChannelLog(ctx context.Context, clog *courier.ChannelLog) error { timeout, cancel := context.WithTimeout(ctx, backendTimeout) defer cancel() diff --git a/backends/rapidpro/log.go b/backends/rapidpro/log.go index fe0280759..a3bf81844 100644 --- a/backends/rapidpro/log.go +++ b/backends/rapidpro/log.go @@ -38,7 +38,7 @@ type channelError struct { } // WriteChannelLog writes the passed in channel log to the database, we do not queue on errors but instead just throw away the log -func writeChannelLog(ctx context.Context, b *backend, clog *courier.ChannelLogger) error { +func writeChannelLog(ctx context.Context, b *backend, clog *courier.ChannelLog) error { dbChan := clog.Channel().(*DBChannel) isError := len(clog.Errors()) > 0 diff --git a/channel_log.go b/channel_log.go index a7be7e90b..8b83fcebc 100644 --- a/channel_log.go +++ b/channel_log.go @@ -36,7 +36,7 @@ func (e *ChannelError) Code() string { return e.code } -type ChannelLogger struct { +type ChannelLog struct { type_ ChannelLogType channel Channel msgID MsgID @@ -47,28 +47,28 @@ type ChannelLogger struct { elapsed time.Duration } -func NewChannelLogForIncoming(r *httpx.Recorder, channel Channel) *ChannelLogger { - return &ChannelLogger{type_: ChannelLogTypeUnknown, recorder: r, channel: channel, createdOn: dates.Now()} +func NewChannelLogForIncoming(r *httpx.Recorder, channel Channel) *ChannelLog { + return &ChannelLog{type_: ChannelLogTypeUnknown, recorder: r, channel: channel, createdOn: dates.Now()} } -func NewChannelLogForSend(msg Msg) *ChannelLogger { - return &ChannelLogger{type_: ChannelLogTypeMsgSend, channel: msg.Channel(), msgID: msg.ID(), createdOn: dates.Now()} +func NewChannelLogForSend(msg Msg) *ChannelLog { + return &ChannelLog{type_: ChannelLogTypeMsgSend, channel: msg.Channel(), msgID: msg.ID(), createdOn: dates.Now()} } -func NewChannelLog(t ChannelLogType, channel Channel) *ChannelLogger { - return &ChannelLogger{type_: t, channel: channel, createdOn: dates.Now()} +func NewChannelLog(t ChannelLogType, channel Channel) *ChannelLog { + return &ChannelLog{type_: t, channel: channel, createdOn: dates.Now()} } // HTTP logs an outgoing HTTP request and response -func (l *ChannelLogger) HTTP(t *httpx.Trace) { +func (l *ChannelLog) HTTP(t *httpx.Trace) { l.httpLogs = append(l.httpLogs, l.traceToLog(t)) } -func (l *ChannelLogger) Error(err error) { +func (l *ChannelLog) Error(err error) { l.errors = append(l.errors, NewChannelError(err.Error(), "")) } -func (l *ChannelLogger) End() { +func (l *ChannelLog) End() { if l.recorder != nil { // prepend so it's the first HTTP request in the log l.httpLogs = append([]*httpx.Log{l.traceToLog(l.recorder.Trace)}, l.httpLogs...) @@ -77,42 +77,42 @@ func (l *ChannelLogger) End() { l.elapsed = time.Since(l.createdOn) } -func (l *ChannelLogger) Type() ChannelLogType { +func (l *ChannelLog) Type() ChannelLogType { return l.type_ } -func (l *ChannelLogger) SetType(t ChannelLogType) { +func (l *ChannelLog) SetType(t ChannelLogType) { l.type_ = t } -func (l *ChannelLogger) Channel() Channel { +func (l *ChannelLog) Channel() Channel { return l.channel } -func (l *ChannelLogger) MsgID() MsgID { +func (l *ChannelLog) MsgID() MsgID { return l.msgID } -func (l *ChannelLogger) SetMsgID(id MsgID) { +func (l *ChannelLog) SetMsgID(id MsgID) { l.msgID = id } -func (l *ChannelLogger) HTTPLogs() []*httpx.Log { +func (l *ChannelLog) HTTPLogs() []*httpx.Log { return l.httpLogs } -func (l *ChannelLogger) Errors() []ChannelError { +func (l *ChannelLog) Errors() []ChannelError { return l.errors } -func (l *ChannelLogger) CreatedOn() time.Time { +func (l *ChannelLog) CreatedOn() time.Time { return l.createdOn } -func (l *ChannelLogger) Elapsed() time.Duration { +func (l *ChannelLog) Elapsed() time.Duration { return l.elapsed } -func (l *ChannelLogger) traceToLog(t *httpx.Trace) *httpx.Log { +func (l *ChannelLog) traceToLog(t *httpx.Trace) *httpx.Log { return httpx.NewLog(t, 2048, 50000, nil) } diff --git a/handler.go b/handler.go index 1aab538b5..d7a600839 100644 --- a/handler.go +++ b/handler.go @@ -16,7 +16,7 @@ type Event interface { // The Server will take care of looking up the channel by UUID before passing it to this function. // Errors in format of the request or by the caller should be handled and logged internally. Errors in // execution or in courier itself should be passed back. -type ChannelHandleFunc func(context.Context, Channel, http.ResponseWriter, *http.Request, *ChannelLogger) ([]Event, error) +type ChannelHandleFunc func(context.Context, Channel, http.ResponseWriter, *http.Request, *ChannelLog) ([]Event, error) // ChannelHandler is the interface all handlers must satisfy type ChannelHandler interface { @@ -25,12 +25,12 @@ type ChannelHandler interface { ChannelName() string UseChannelRouteUUID() bool GetChannel(context.Context, *http.Request) (Channel, error) - Send(context.Context, Msg, *ChannelLogger) (MsgStatus, error) + Send(context.Context, Msg, *ChannelLog) (MsgStatus, error) } // URNDescriber is the interface handlers which can look up URN metadata for new contacts should satisfy. type URNDescriber interface { - DescribeURN(context.Context, Channel, urns.URN, *ChannelLogger) (map[string]string, error) + DescribeURN(context.Context, Channel, urns.URN, *ChannelLog) (map[string]string, error) } // MediaDownloadRequestBuilder is the interface handlers which can allow a custom way to download attachment media for messages should satisfy diff --git a/handler_test.go b/handler_test.go index 650a62357..1dc2ba44a 100644 --- a/handler_test.go +++ b/handler_test.go @@ -46,12 +46,12 @@ func (h *dummyHandler) Initialize(s courier.Server) error { } // Send sends the given message, logging any HTTP calls or errors -func (h *dummyHandler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *dummyHandler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { return h.backend.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgSent), nil } // ReceiveMsg sends the passed in message, returning any error -func (h *dummyHandler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *dummyHandler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { r.ParseForm() from := r.Form.Get("from") text := r.Form.Get("text") diff --git a/handlers/africastalking/africastalking.go b/handlers/africastalking/africastalking.go index 35ac50ac6..248e79ce7 100644 --- a/handlers/africastalking/africastalking.go +++ b/handlers/africastalking/africastalking.go @@ -48,7 +48,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -94,7 +94,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // get our params form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -114,7 +114,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { isSharedStr := msg.Channel().ConfigForKey(configIsShared, false) isShared, _ := isSharedStr.(bool) diff --git a/handlers/arabiacell/arabiacell.go b/handlers/arabiacell/arabiacell.go index 1c949086f..f1b12da15 100644 --- a/handlers/arabiacell/arabiacell.go +++ b/handlers/arabiacell/arabiacell.go @@ -56,7 +56,7 @@ type mtResponse struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for AC channel") diff --git a/handlers/blackmyna/blackmyna.go b/handlers/blackmyna/blackmyna.go index ad1bd60a4..723d76d48 100644 --- a/handlers/blackmyna/blackmyna.go +++ b/handlers/blackmyna/blackmyna.go @@ -42,7 +42,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -76,7 +76,7 @@ var statusMapping = map[int]courier.MsgStatusValue{ } // StatusMessage is our HTTP handler function for status updates -func (h *handler) StatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) StatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // get our params form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -95,7 +95,7 @@ func (h *handler) StatusMessage(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for BM channel") diff --git a/handlers/bongolive/bongolive.go b/handlers/bongolive/bongolive.go index f4c9374e1..507383430 100644 --- a/handlers/bongolive/bongolive.go +++ b/handlers/bongolive/bongolive.go @@ -64,7 +64,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { var err error form := &moForm{} err = handlers.DecodeAndValidateForm(form, r) @@ -124,7 +124,7 @@ func writeBongoLiveResponse(w http.ResponseWriter) error { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for %s channel", msg.Channel().ChannelType()) diff --git a/handlers/burstsms/burstsms.go b/handlers/burstsms/burstsms.go index 68103d58d..3c4b8c1fb 100644 --- a/handlers/burstsms/burstsms.go +++ b/handlers/burstsms/burstsms.go @@ -56,7 +56,7 @@ type mtResponse struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for BS channel") diff --git a/handlers/chikka/chikka.go b/handlers/chikka/chikka.go index 7485e7472..f7d35d766 100644 --- a/handlers/chikka/chikka.go +++ b/handlers/chikka/chikka.go @@ -56,7 +56,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) @@ -104,7 +104,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for CK channel") diff --git a/handlers/clickatell/clickatell.go b/handlers/clickatell/clickatell.go index 4f88c3421..2cf8d6267 100644 --- a/handlers/clickatell/clickatell.go +++ b/handlers/clickatell/clickatell.go @@ -65,7 +65,7 @@ var statusMapping = map[int]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &statusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) @@ -99,7 +99,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) @@ -169,7 +169,7 @@ func decodeUTF16BE(b []byte) (string, error) { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { apiKey := msg.Channel().StringConfigForKey(courier.ConfigAPIKey, "") if apiKey == "" { return nil, fmt.Errorf("no api_key set for CT channel") diff --git a/handlers/clickmobile/clickmobile.go b/handlers/clickmobile/clickmobile.go index b5ab632a5..9cbb09378 100644 --- a/handlers/clickmobile/clickmobile.go +++ b/handlers/clickmobile/clickmobile.go @@ -59,7 +59,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateXML(payload, r) if err != nil { @@ -98,7 +98,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for CM channel") diff --git a/handlers/clicksend/clicksend.go b/handlers/clicksend/clicksend.go index 3248d15a3..824c3e0aa 100644 --- a/handlers/clicksend/clicksend.go +++ b/handlers/clicksend/clicksend.go @@ -61,7 +61,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("Missing 'username' config for CS channel") diff --git a/handlers/dart/dart.go b/handlers/dart/dart.go index 8c723a912..6ee4b9b0d 100644 --- a/handlers/dart/dart.go +++ b/handlers/dart/dart.go @@ -56,7 +56,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -89,7 +89,7 @@ type statusForm struct { } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -139,7 +139,7 @@ func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWr } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for %s channel", msg.Channel().ChannelType()) diff --git a/handlers/discord/discord.go b/handlers/discord/discord.go index bf613c9ab..8b239586b 100644 --- a/handlers/discord/discord.go +++ b/handlers/discord/discord.go @@ -69,7 +69,7 @@ func getFormField(form url.Values, name string) string { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { var err error var from, text string @@ -119,7 +119,7 @@ func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWr // buildStatusHandler deals with building a handler that takes what status is received in the URL func (h *handler) buildStatusHandler(status string) courier.ChannelHandleFunc { - return func(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { + return func(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { return h.receiveStatus(ctx, status, channel, w, r, clog) } } @@ -135,7 +135,7 @@ var statusMappings = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, statusString string, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, statusString string, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -154,7 +154,7 @@ func (h *handler) receiveStatus(ctx context.Context, statusString string, channe } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { sendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, "") if sendURL == "" { return nil, fmt.Errorf("no send url set for DS channel") diff --git a/handlers/dmark/dmark.go b/handlers/dmark/dmark.go index 4ec72773e..f4b2c126b 100644 --- a/handlers/dmark/dmark.go +++ b/handlers/dmark/dmark.go @@ -47,7 +47,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -88,7 +88,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // get our params form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -107,7 +107,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { // get our authentication token auth := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if auth == "" { diff --git a/handlers/external/external.go b/handlers/external/external.go index da55bc584..d646fe831 100644 --- a/handlers/external/external.go +++ b/handlers/external/external.go @@ -93,7 +93,7 @@ type stopContactForm struct { From string `validate:"required" name:"from"` } -func (h *handler) receiveStopContact(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStopContact(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &stopContactForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -142,7 +142,7 @@ func getFormField(form url.Values, defaultNames []string, name string) string { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { var err error var from, dateString, text string @@ -238,7 +238,7 @@ func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWr // buildStatusHandler deals with building a handler that takes what status is received in the URL func (h *handler) buildStatusHandler(status string) courier.ChannelHandleFunc { - return func(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { + return func(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { return h.receiveStatus(ctx, status, channel, w, r, clog) } } @@ -254,7 +254,7 @@ var statusMappings = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, statusString string, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, statusString string, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -273,7 +273,7 @@ func (h *handler) receiveStatus(ctx context.Context, statusString string, channe } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { sendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, "") if sendURL == "" { return nil, fmt.Errorf("no send url set for EX channel") diff --git a/handlers/facebook/facebook.go b/handlers/facebook/facebook.go index 12522ca31..446ba6ec7 100644 --- a/handlers/facebook/facebook.go +++ b/handlers/facebook/facebook.go @@ -77,7 +77,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveVerify handles Facebook's webhook verification callback -func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { mode := r.URL.Query().Get("hub.mode") // this isn't a subscribe verification, that's an error @@ -206,7 +206,7 @@ type moPayload struct { } // receiveEvent is our HTTP handler function for incoming messages and status updates -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -473,7 +473,7 @@ type mtQuickReply struct { ContentType string `json:"content_type"` } -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { // can't do anything without an access token accessToken := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if accessToken == "" { @@ -615,7 +615,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } // DescribeURN looks up URN metadata for new contacts -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLogger) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLog) (map[string]string, error) { // can't do anything with facebook refs, ignore them if urn.IsFacebookRef() { return map[string]string{}, nil diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index 09814f324..60174839d 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -495,7 +495,7 @@ func TestDescribe(t *testing.T) { channel := testChannels[0] handler := newHandler().(courier.URNDescriber) - logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) tcs := []struct { urn urns.URN @@ -507,7 +507,7 @@ func TestDescribe(t *testing.T) { } for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), channel, tc.urn, logger) + metadata, _ := handler.DescribeURN(context.Background(), channel, tc.urn, clog) assert.Equal(t, metadata, tc.expectedMetadata) } } diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 24b16f8bc..c4228df6f 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -312,7 +312,7 @@ func (h *handler) GetChannel(ctx context.Context, r *http.Request) (courier.Chan } // receiveVerify handles Facebook's webhook verification callback -func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { mode := r.URL.Query().Get("hub.mode") // this isn't a subscribe verification, that's an error @@ -354,7 +354,7 @@ func resolveMediaURL(mediaID string, token string) (string, error) { } // receiveEvent is our HTTP handler function for incoming messages and status updates -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { err := h.validateSignature(r) if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) @@ -803,7 +803,7 @@ type mtQuickReply struct { ContentType string `json:"content_type"` } -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { if msg.Channel().ChannelType() == "FBA" || msg.Channel().ChannelType() == "IG" { return h.sendFacebookInstagramMsg(ctx, msg, clog) } else if msg.Channel().ChannelType() == "WAC" { @@ -813,7 +813,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("unssuported channel type") } -func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { // can't do anything without an access token accessToken := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if accessToken == "" { @@ -1055,7 +1055,7 @@ type wacMTResponse struct { } `json:"messages"` } -func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { // can't do anything without an access token accessToken := h.Server().Config().WhatsappAdminSystemUserToken @@ -1297,7 +1297,7 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, } // DescribeURN looks up URN metadata for new contacts -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLogger) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLog) (map[string]string, error) { if channel.ChannelType() == "WAC" { return map[string]string{}, nil } diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 2613d9be3..8b8f530f8 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -191,7 +191,7 @@ func TestDescribeFBA(t *testing.T) { channel := testChannelsFBA[0] handler := newHandler("FBA", "Facebook", false).(courier.URNDescriber) - logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) tcs := []struct { urn urns.URN @@ -203,7 +203,7 @@ func TestDescribeFBA(t *testing.T) { } for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), channel, tc.urn, logger) + metadata, _ := handler.DescribeURN(context.Background(), channel, tc.urn, clog) assert.Equal(t, metadata, tc.expectedMetadata) } } @@ -214,7 +214,7 @@ func TestDescribeIG(t *testing.T) { channel := testChannelsIG[0] handler := newHandler("IG", "Instagram", false).(courier.URNDescriber) - logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) tcs := []struct { urn urns.URN @@ -225,7 +225,7 @@ func TestDescribeIG(t *testing.T) { } for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), channel, tc.urn, logger) + metadata, _ := handler.DescribeURN(context.Background(), channel, tc.urn, clog) assert.Equal(t, metadata, tc.expectedMetadata) } } @@ -233,7 +233,7 @@ func TestDescribeIG(t *testing.T) { func TestDescribeWAC(t *testing.T) { channel := testChannelsWAC[0] handler := newHandler("WAC", "Cloud API WhatsApp", false).(courier.URNDescriber) - logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) tcs := []struct { urn urns.URN @@ -244,7 +244,7 @@ func TestDescribeWAC(t *testing.T) { } for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), testChannelsWAC[0], tc.urn, logger) + metadata, _ := handler.DescribeURN(context.Background(), testChannelsWAC[0], tc.urn, clog) assert.Equal(t, metadata, tc.expectedMetadata) } } diff --git a/handlers/firebase/firebase.go b/handlers/firebase/firebase.go index bcee98dff..82e276fed 100644 --- a/handlers/firebase/firebase.go +++ b/handlers/firebase/firebase.go @@ -54,7 +54,7 @@ type receiveForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &receiveForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -89,7 +89,7 @@ type registerForm struct { } // registerContact is our HTTP handler function for when a contact is registered (or renewed) -func (h *handler) registerContact(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) registerContact(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := ®isterForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -135,7 +135,7 @@ type mtNotification struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { title := msg.Channel().StringConfigForKey(configTitle, "") if title == "" { return nil, fmt.Errorf("no FCM_TITLE set for FCM channel") diff --git a/handlers/freshchat/freshchat.go b/handlers/freshchat/freshchat.go index e92857e19..7d28ee7dd 100644 --- a/handlers/freshchat/freshchat.go +++ b/handlers/freshchat/freshchat.go @@ -48,7 +48,7 @@ func (h *handler) Initialize(s courier.Server) error { s.AddHandlerRoute(h, http.MethodPost, "receive", h.receiveMessage) return nil } -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { err := h.validateSignature(channel, r) if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) @@ -101,7 +101,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) } -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { agentID := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if agentID == "" { diff --git a/handlers/generic.go b/handlers/generic.go index 0fd991e01..3793cadf4 100644 --- a/handlers/generic.go +++ b/handlers/generic.go @@ -11,7 +11,7 @@ import ( // NewTelReceiveHandler creates a new receive handler given the passed in text and from fields func NewTelReceiveHandler(h *BaseHandler, fromField string, bodyField string) courier.ChannelHandleFunc { - return func(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { + return func(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, WriteAndLogRequestError(ctx, h, c, w, r, err) @@ -35,7 +35,7 @@ func NewTelReceiveHandler(h *BaseHandler, fromField string, bodyField string) co // NewExternalIDStatusHandler creates a new status handler given the passed in status map and fields func NewExternalIDStatusHandler(h *BaseHandler, statuses map[string]courier.MsgStatusValue, externalIDField string, statusField string) courier.ChannelHandleFunc { - return func(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { + return func(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, WriteAndLogRequestError(ctx, h, c, w, r, err) diff --git a/handlers/globe/globe.go b/handlers/globe/globe.go index cec69dab7..d4b02cff9 100644 --- a/handlers/globe/globe.go +++ b/handlers/globe/globe.go @@ -73,7 +73,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -126,7 +126,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { appID := msg.Channel().StringConfigForKey(configAppID, "") if appID == "" { return nil, fmt.Errorf("Missing 'app_id' config for GL channel") diff --git a/handlers/highconnection/highconnection.go b/handlers/highconnection/highconnection.go index 61d1b6be9..c5f058be1 100644 --- a/handlers/highconnection/highconnection.go +++ b/handlers/highconnection/highconnection.go @@ -46,7 +46,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -98,7 +98,7 @@ var statusMapping = map[int]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -116,7 +116,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for HX channel") diff --git a/handlers/hormuud/hormuud.go b/handlers/hormuud/hormuud.go index 09acebb7d..6da7ec3b9 100644 --- a/handlers/hormuud/hormuud.go +++ b/handlers/hormuud/hormuud.go @@ -51,7 +51,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateForm(payload, r) if err != nil { @@ -80,7 +80,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) token, err := h.FetchToken(ctx, msg.Channel(), msg, clog) @@ -133,7 +133,7 @@ type tokenResponse struct { } // FetchToken gets the current token for this channel, either from Redis if cached or by requesting it -func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg courier.Msg, clog *courier.ChannelLogger) (string, error) { +func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg courier.Msg, clog *courier.ChannelLog) (string, error) { // first check whether we have it in redis conn := h.Backend().RedisPool().Get() token, err := redis.String(conn.Do("GET", fmt.Sprintf("hm_token_%s", channel.UUID()))) diff --git a/handlers/http.go b/handlers/http.go index 479293d5f..31e988a3a 100644 --- a/handlers/http.go +++ b/handlers/http.go @@ -10,18 +10,18 @@ import ( ) // RequestHTTP does the given request, logging the trace, and returns the response -func RequestHTTP(req *http.Request, clog *courier.ChannelLogger) (*http.Response, []byte, error) { +func RequestHTTP(req *http.Request, clog *courier.ChannelLog) (*http.Response, []byte, error) { return RequestHTTPWithClient(utils.GetHTTPClient(), req, clog) } // RequestHTTPInsecure does the given request using an insecure client that does not validate SSL certificates, // logging the trace, and returns the response -func RequestHTTPInsecure(req *http.Request, clog *courier.ChannelLogger) (*http.Response, []byte, error) { +func RequestHTTPInsecure(req *http.Request, clog *courier.ChannelLog) (*http.Response, []byte, error) { return RequestHTTPWithClient(utils.GetInsecureHTTPClient(), req, clog) } // RequestHTTP does the given request using the given client, logging the trace, and returns the response -func RequestHTTPWithClient(client *http.Client, req *http.Request, clog *courier.ChannelLogger) (*http.Response, []byte, error) { +func RequestHTTPWithClient(client *http.Client, req *http.Request, clog *courier.ChannelLog) (*http.Response, []byte, error) { var resp *http.Response var body []byte diff --git a/handlers/i2sms/i2sms.go b/handlers/i2sms/i2sms.go index cc3009811..21febb54d 100644 --- a/handlers/i2sms/i2sms.go +++ b/handlers/i2sms/i2sms.go @@ -42,7 +42,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receive is our handler for MO messages -func (h *handler) receive(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receive(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, err) @@ -83,7 +83,7 @@ type mtResponse struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for I2 channel") diff --git a/handlers/infobip/infobip.go b/handlers/infobip/infobip.go index 7773754b2..1e14686d0 100644 --- a/handlers/infobip/infobip.go +++ b/handlers/infobip/infobip.go @@ -58,7 +58,7 @@ type ibStatus struct { } // statusMessage is our HTTP handler function for status updates -func (h *handler) statusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) statusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &statusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -126,7 +126,7 @@ type moMessage struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -175,7 +175,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for IB channel") diff --git a/handlers/jasmin/jasmin.go b/handlers/jasmin/jasmin.go index c4b3dd9ab..962cf4f77 100644 --- a/handlers/jasmin/jasmin.go +++ b/handlers/jasmin/jasmin.go @@ -43,7 +43,7 @@ type statusForm struct { } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -73,7 +73,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -119,7 +119,7 @@ func writeJasminACK(w http.ResponseWriter) error { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for JS channel") diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index fe72ba914..30fb0b692 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -64,7 +64,7 @@ type verifyForm struct { } // VerifyURL is our HTTP handler function for Jiochat config URL verification callbacks -func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &verifyForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -109,7 +109,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -234,7 +234,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { accessToken, err := h.getAccessToken(msg.Channel()) if err != nil { return nil, err @@ -269,7 +269,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } // DescribeURN handles Jiochat contact details -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLogger) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLog) (map[string]string, error) { accessToken, err := h.getAccessToken(channel) if err != nil { return nil, err diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index 70b900bc6..b8aee0466 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -272,7 +272,7 @@ func TestDescribeURN(t *testing.T) { s := newServer(mb) handler := &handler{handlers.NewBaseHandler(courier.ChannelType("JC"), "Jiochat")} handler.Initialize(s) - logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) tcs := []struct { urn urns.URN @@ -283,7 +283,7 @@ func TestDescribeURN(t *testing.T) { } for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), testChannels[0], tc.urn, logger) + metadata, _ := handler.DescribeURN(context.Background(), testChannels[0], tc.urn, clog) assert.Equal(t, metadata, tc.expectedMetadata) } } diff --git a/handlers/junebug/junebug.go b/handlers/junebug/junebug.go index e1a02465f..2d27a12d8 100644 --- a/handlers/junebug/junebug.go +++ b/handlers/junebug/junebug.go @@ -56,7 +56,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -108,7 +108,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveEvent is our HTTP handler function for incoming events -func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &eventPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -154,7 +154,7 @@ type mtPayload struct { EventAuthToken string `json:"event_auth_token,omitempty"` } -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { sendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, "") if sendURL == "" { return nil, fmt.Errorf("No send_url set for JN channel") diff --git a/handlers/kaleyra/kaleyra.go b/handlers/kaleyra/kaleyra.go index 9af9adb89..39c0f09cf 100644 --- a/handlers/kaleyra/kaleyra.go +++ b/handlers/kaleyra/kaleyra.go @@ -65,7 +65,7 @@ type moStatusForm struct { } // receiveMsg is our HTTP handler function for incoming messages -func (h *handler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &moMsgForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -113,7 +113,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for outgoing messages statuses -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &moStatusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -137,7 +137,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { accountSID := msg.Channel().StringConfigForKey(configAccountSID, "") apiKey := msg.Channel().StringConfigForKey(configApiKey, "") diff --git a/handlers/kannel/kannel.go b/handlers/kannel/kannel.go index bf476d135..d636f8203 100644 --- a/handlers/kannel/kannel.go +++ b/handlers/kannel/kannel.go @@ -56,7 +56,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -94,7 +94,7 @@ type statusForm struct { } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // get our params form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -119,7 +119,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for KN channel") diff --git a/handlers/line/line.go b/handlers/line/line.go index cd6d3773d..8219dd6c2 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -112,7 +112,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { err := h.validateSignature(channel, r) if err != nil { return nil, err @@ -285,7 +285,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { authToken := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if authToken == "" { return nil, fmt.Errorf("no auth token set for LN channel: %s", msg.Channel().UUID()) diff --git a/handlers/m3tech/m3tech.go b/handlers/m3tech/m3tech.go index e8575b494..e6a297c7f 100644 --- a/handlers/m3tech/m3tech.go +++ b/handlers/m3tech/m3tech.go @@ -38,7 +38,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveMessage takes care of handling incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, err) @@ -69,7 +69,7 @@ func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWr } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for M3 channel") diff --git a/handlers/macrokiosk/macrokiosk.go b/handlers/macrokiosk/macrokiosk.go index 7e7ab4e99..323e567be 100644 --- a/handlers/macrokiosk/macrokiosk.go +++ b/handlers/macrokiosk/macrokiosk.go @@ -61,7 +61,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -89,7 +89,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -152,7 +152,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") password := msg.Channel().StringConfigForKey(courier.ConfigPassword, "") servID := msg.Channel().StringConfigForKey(configMacrokioskServiceID, "") diff --git a/handlers/mblox/mblox.go b/handlers/mblox/mblox.go index c52ad82e9..a2c6d04e1 100644 --- a/handlers/mblox/mblox.go +++ b/handlers/mblox/mblox.go @@ -60,7 +60,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveEvent is our HTTP handler function for incoming messages -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &eventPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -115,7 +115,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") password := msg.Channel().StringConfigForKey(courier.ConfigPassword, "") if username == "" || password == "" { diff --git a/handlers/messangi/messangi.go b/handlers/messangi/messangi.go index 833ce890e..bf41cf78e 100644 --- a/handlers/messangi/messangi.go +++ b/handlers/messangi/messangi.go @@ -60,7 +60,7 @@ type mtResponse struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { publicKey := msg.Channel().StringConfigForKey(configPublicKey, "") if publicKey == "" { return nil, fmt.Errorf("no public_key set for MG channel") diff --git a/handlers/mtarget/mtarget.go b/handlers/mtarget/mtarget.go index acb167fa9..f2d9c1dfd 100644 --- a/handlers/mtarget/mtarget.go +++ b/handlers/mtarget/mtarget.go @@ -52,7 +52,7 @@ func (h *handler) Initialize(s courier.Server) error { } // ReceiveMsg handles both MO messages and Stop commands -func (h *handler) receiveMsg(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMsg(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { err := r.ParseForm() if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, err) @@ -148,7 +148,7 @@ func (h *handler) receiveMsg(ctx context.Context, c courier.Channel, w http.Resp } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for MT channel") diff --git a/handlers/nexmo/nexmo.go b/handlers/nexmo/nexmo.go index a5829ab0c..602d78fbb 100644 --- a/handlers/nexmo/nexmo.go +++ b/handlers/nexmo/nexmo.go @@ -70,7 +70,7 @@ var statusMappings = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &statusForm{} handlers.DecodeAndValidateForm(form, r) @@ -96,7 +96,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &moForm{} handlers.DecodeAndValidateForm(form, r) @@ -117,7 +117,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { nexmoAPIKey := msg.Channel().StringConfigForKey(configNexmoAPIKey, "") if nexmoAPIKey == "" { return nil, fmt.Errorf("no nexmo API key set for NX channel") diff --git a/handlers/novo/novo.go b/handlers/novo/novo.go index 9d72baf19..095ea5c73 100644 --- a/handlers/novo/novo.go +++ b/handlers/novo/novo.go @@ -45,7 +45,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // check authentication secret := c.StringConfigForKey(courier.ConfigSecret, "") if secret != "" { @@ -78,7 +78,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { merchantID := msg.Channel().StringConfigForKey(configMerchantId, "") if merchantID == "" { return nil, fmt.Errorf("no merchant_id set for NV channel") diff --git a/handlers/playmobile/playmobile.go b/handlers/playmobile/playmobile.go index 5592bf89d..63edeeb20 100644 --- a/handlers/playmobile/playmobile.go +++ b/handlers/playmobile/playmobile.go @@ -92,7 +92,7 @@ type mtResponse struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &mtResponse{} err := handlers.DecodeAndValidateXML(payload, r) @@ -145,7 +145,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(configUsername, "") if username == "" { return nil, fmt.Errorf("no username set for PM channel") diff --git a/handlers/plivo/plivo.go b/handlers/plivo/plivo.go index 12fc6c255..0509db49e 100644 --- a/handlers/plivo/plivo.go +++ b/handlers/plivo/plivo.go @@ -70,7 +70,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -104,7 +104,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -136,7 +136,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { authID := msg.Channel().StringConfigForKey(configPlivoAuthID, "") authToken := msg.Channel().StringConfigForKey(configPlivoAuthToken, "") plivoAppID := msg.Channel().StringConfigForKey(configPlivoAPPID, "") diff --git a/handlers/redrabbit/redrabbit.go b/handlers/redrabbit/redrabbit.go index 503a7e397..c31d9a3b9 100644 --- a/handlers/redrabbit/redrabbit.go +++ b/handlers/redrabbit/redrabbit.go @@ -36,7 +36,7 @@ func (h *handler) Initialize(s courier.Server) error { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") password := msg.Channel().StringConfigForKey(courier.ConfigPassword, "") if username == "" || password == "" { diff --git a/handlers/rocketchat/rocketchat.go b/handlers/rocketchat/rocketchat.go index 7e8e564fb..17e080567 100644 --- a/handlers/rocketchat/rocketchat.go +++ b/handlers/rocketchat/rocketchat.go @@ -57,7 +57,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // check authorization secret := channel.StringConfigForKey(configSecret, "") if fmt.Sprintf("Token %s", secret) != r.Header.Get("Authorization") { @@ -109,7 +109,7 @@ type mtPayload struct { Attachments []Attachment `json:"attachments,omitempty"` } -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { baseURL := msg.Channel().StringConfigForKey(configBaseURL, "") secret := msg.Channel().StringConfigForKey(configSecret, "") botUsername := msg.Channel().StringConfigForKey(configBotUsername, "") diff --git a/handlers/shaqodoon/shaqodoon.go b/handlers/shaqodoon/shaqodoon.go index a619ab232..4999ab175 100644 --- a/handlers/shaqodoon/shaqodoon.go +++ b/handlers/shaqodoon/shaqodoon.go @@ -45,7 +45,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -84,7 +84,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { sendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, "") if sendURL == "" { return nil, fmt.Errorf("missing send_url for SQ channel") diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index 16adbde53..a172f6fee 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -62,7 +62,7 @@ func handleURLVerification(ctx context.Context, channel courier.Channel, w http. return nil, nil } -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -105,7 +105,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "Ignoring request, no message") } -func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file File, clog *courier.ChannelLogger) (string, error) { +func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file File, clog *courier.ChannelLog) (string, error) { userToken := channel.StringConfigForKey(configUserToken, "") fileApiURL := apiURL + "/files.sharedPublicURL" @@ -148,7 +148,7 @@ func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file return filePath, nil } -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { botToken := msg.Channel().StringConfigForKey(configBotToken, "") if botToken == "" { return nil, fmt.Errorf("missing bot token for SL/slack channel") @@ -184,7 +184,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } -func sendTextMsgPart(msg courier.Msg, token string, clog *courier.ChannelLogger) error { +func sendTextMsgPart(msg courier.Msg, token string, clog *courier.ChannelLog) error { sendURL := apiURL + "/chat.postMessage" msgPayload := &mtPayload{ @@ -224,7 +224,7 @@ func sendTextMsgPart(msg courier.Msg, token string, clog *courier.ChannelLogger) return nil } -func parseAttachmentToFileParams(msg courier.Msg, attachment string, clog *courier.ChannelLogger) (*FileParams, error) { +func parseAttachmentToFileParams(msg courier.Msg, attachment string, clog *courier.ChannelLog) (*FileParams, error) { _, attURL := handlers.SplitAttachment(attachment) req, err := http.NewRequest(http.MethodGet, attURL, nil) @@ -244,7 +244,7 @@ func parseAttachmentToFileParams(msg courier.Msg, attachment string, clog *couri return &FileParams{File: respBody, FileName: filename, Channels: msg.URN().Path()}, nil } -func sendFilePart(msg courier.Msg, token string, fileParams *FileParams, clog *courier.ChannelLogger) error { +func sendFilePart(msg courier.Msg, token string, fileParams *FileParams, clog *courier.ChannelLog) error { uploadURL := apiURL + "/files.upload" body := &bytes.Buffer{} @@ -294,7 +294,7 @@ func sendFilePart(msg courier.Msg, token string, fileParams *FileParams, clog *c } // DescribeURN handles Slack user details -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLogger) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLog) (map[string]string, error) { resource := "/users.info" urlStr := apiURL + resource diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 6aa006df1..4656032dc 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -360,12 +360,12 @@ func TestDescribeURN(t *testing.T) { defer server.Close() handler := newHandler().(courier.URNDescriber) - logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) urn, _ := urns.NewURNFromParts(urns.SlackScheme, "U012345", "", "") data := map[string]string{"name": "dummy user"} - describe, err := handler.DescribeURN(context.Background(), testChannels[0], urn, logger) + describe, err := handler.DescribeURN(context.Background(), testChannels[0], urn, clog) assert.Nil(t, err) assert.Equal(t, data, describe) } diff --git a/handlers/smscentral/smscentral.go b/handlers/smscentral/smscentral.go index 8c19150e7..e28fb57da 100644 --- a/handlers/smscentral/smscentral.go +++ b/handlers/smscentral/smscentral.go @@ -43,7 +43,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -63,7 +63,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for SC channel") diff --git a/handlers/start/start.go b/handlers/start/start.go index 987f525bc..bbd7c2c17 100644 --- a/handlers/start/start.go +++ b/handlers/start/start.go @@ -56,7 +56,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateXML(payload, r) if err != nil { @@ -120,7 +120,7 @@ type mtResponse struct { State string `xml:"state"` } -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for ST channel: %s", msg.Channel().UUID()) diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index 8f75186cb..fcfb82fff 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -49,7 +49,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -149,7 +149,7 @@ type mtResponse struct { } `json:"result"` } -func (h *handler) sendMsgPart(msg courier.Msg, token string, path string, form url.Values, keyboard *ReplyKeyboardMarkup, clog *courier.ChannelLogger) (string, bool, error) { +func (h *handler) sendMsgPart(msg courier.Msg, token string, path string, form url.Values, keyboard *ReplyKeyboardMarkup, clog *courier.ChannelLog) (string, bool, error) { // either include or remove our keyboard if keyboard == nil { form.Add("reply_markup", `{"remove_keyboard":true}`) @@ -184,7 +184,7 @@ func (h *handler) sendMsgPart(msg courier.Msg, token string, path string, form u } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { confAuth := msg.Channel().ConfigForKey(courier.ConfigAuthToken, "") authToken, isStr := confAuth.(string) if !isStr || authToken == "" { @@ -324,7 +324,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } -func (h *handler) resolveFileID(ctx context.Context, channel courier.Channel, fileID string, clog *courier.ChannelLogger) (string, error) { +func (h *handler) resolveFileID(ctx context.Context, channel courier.Channel, fileID string, clog *courier.ChannelLog) (string, error) { confAuth := channel.ConfigForKey(courier.ConfigAuthToken, "") authToken, isStr := confAuth.(string) if !isStr || authToken == "" { diff --git a/handlers/telesom/telesom.go b/handlers/telesom/telesom.go index 7d3efbd7f..eac867620 100644 --- a/handlers/telesom/telesom.go +++ b/handlers/telesom/telesom.go @@ -44,7 +44,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -65,7 +65,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for TS channel") diff --git a/handlers/thinq/thinq.go b/handlers/thinq/thinq.go index febc6379d..119a5cba5 100644 --- a/handlers/thinq/thinq.go +++ b/handlers/thinq/thinq.go @@ -55,7 +55,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // get our params form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -103,7 +103,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // get our params form := &statusForm{} err := handlers.DecodeAndValidateForm(form, r) @@ -129,7 +129,7 @@ type mtMessage struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { accountID := msg.Channel().StringConfigForKey(configAccountID, "") if accountID == "" { return nil, fmt.Errorf("no account id set for TQ channel") diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index c992af303..855e5ad6f 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -100,7 +100,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { err := h.validateSignature(channel, r) if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) @@ -140,7 +140,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { err := h.validateSignature(channel, r) if err != nil { return nil, err @@ -200,7 +200,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { // build our callback URL callbackDomain := msg.Channel().CallbackDomain(h.Server().Config().Domain) callbackURL := fmt.Sprintf("https://%s/c/%s/%s/status?id=%d&action=callback", callbackDomain, strings.ToLower(h.ChannelType().String()), msg.Channel().UUID(), msg.ID()) diff --git a/handlers/twitter/twitter.go b/handlers/twitter/twitter.go index 0dd627203..f521edf80 100644 --- a/handlers/twitter/twitter.go +++ b/handlers/twitter/twitter.go @@ -65,7 +65,7 @@ func (h *handler) Initialize(s courier.Server) error { } // receiveVerify handles Twitter's webhook verification callback -func (h *handler) receiveVerify(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveVerify(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { crcToken := r.URL.Query().Get("crc_token") if crcToken == "" { return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, fmt.Errorf(`missing required 'crc_token' query parameter`)) @@ -134,7 +134,7 @@ type moPayload struct { } // receiveEvent is our HTTP handler function for incoming events -func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // read our handle id handleID := c.StringConfigForKey(configHandleID, "") if handleID == "" { @@ -255,7 +255,7 @@ type mtAttachment struct { } `json:"media"` } -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { apiKey := msg.Channel().StringConfigForKey(configAPIKey, "") apiSecret := msg.Channel().StringConfigForKey(configAPISecret, "") accessToken := msg.Channel().StringConfigForKey(configAccessToken, "") @@ -370,7 +370,7 @@ func generateSignature(secret string, content string) string { return base64.StdEncoding.EncodeToString(h.Sum(nil)) } -func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType string, attachmentURL string, client *http.Client, clog *courier.ChannelLogger) (string, error) { +func uploadMediaToTwitter(msg courier.Msg, mediaUrl string, attachmentMimeType string, attachmentURL string, client *http.Client, clog *courier.ChannelLog) (string, error) { // retrieve the media to be sent from S3 req, _ := http.NewRequest(http.MethodGet, attachmentURL, nil) diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index 2e0011416..40bc5350a 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -89,7 +89,7 @@ type welcomeMessagePayload struct { } // receiveEvent is our HTTP handler function for incoming messages -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { err := h.validateSignature(channel, r) if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) @@ -309,7 +309,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { authToken := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if authToken == "" { return nil, fmt.Errorf("missing auth token in config") diff --git a/handlers/vk/vk.go b/handlers/vk/vk.go index 2f556390e..94173a525 100644 --- a/handlers/vk/vk.go +++ b/handlers/vk/vk.go @@ -193,7 +193,7 @@ type mediaUploadInfoPayload struct { } // receiveEvent handles request event type -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // read request body bodyBytes, err := ioutil.ReadAll(io.LimitReader(r.Body, 100000)) @@ -273,7 +273,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // DescribeURN handles VK contact details -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLogger) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLog) (map[string]string, error) { req, err := http.NewRequest(http.MethodPost, apiBaseURL+actionGetUser, nil) if err != nil { return nil, err @@ -386,7 +386,7 @@ func takeFirstAttachmentUrl(payload moNewMessagePayload) string { return "" } -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) params := buildApiBaseParams(msg.Channel()) @@ -428,7 +428,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } // buildTextAndAttachmentParams builds msg text with attachment links (if needed) and attachments list param, also returns the errors that occurred -func buildTextAndAttachmentParams(msg courier.Msg, clog *courier.ChannelLogger) (string, string) { +func buildTextAndAttachmentParams(msg courier.Msg, clog *courier.ChannelLog) (string, string) { var msgAttachments []string textBuf := bytes.Buffer{} diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index 5c551d1e4..9393c5350 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -374,11 +374,11 @@ func TestDescribeURN(t *testing.T) { defer server.Close() handler := newHandler().(courier.URNDescriber) - logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) urn, _ := urns.NewURNFromParts(urns.VKScheme, "123456789", "", "") data := map[string]string{"name": "John Doe"} - describe, err := handler.DescribeURN(context.Background(), testChannels[0], urn, logger) + describe, err := handler.DescribeURN(context.Background(), testChannels[0], urn, clog) assert.Nil(t, err) assert.Equal(t, data, describe) } diff --git a/handlers/wavy/wavy.go b/handlers/wavy/wavy.go index 0daff36c3..c069641df 100644 --- a/handlers/wavy/wavy.go +++ b/handlers/wavy/wavy.go @@ -62,7 +62,7 @@ type sentStatusPayload struct { } // sentStatusMessage is our HTTP handler function for status updates -func (h *handler) sentStatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) sentStatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &sentStatusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -85,7 +85,7 @@ type deliveredStatusPayload struct { } // sentStatusMessage is our HTTP handler function for status updates -func (h *handler) deliveredStatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) deliveredStatusMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &deliveredStatusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -111,7 +111,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -139,7 +139,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for %s channel", msg.Channel().ChannelType()) diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index ff6f8b47e..625c62e45 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -61,7 +61,7 @@ type verifyForm struct { } // VerifyURL is our HTTP handler function for WeChat config URL verification callbacks -func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &verifyForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -168,7 +168,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &moPayload{} err := handlers.DecodeAndValidateXML(payload, r) if err != nil { @@ -235,7 +235,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { accessToken, err := h.getAccessToken(msg.Channel()) if err != nil { return nil, err @@ -279,7 +279,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } // DescribeURN handles WeChat contact details -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLogger) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLog) (map[string]string, error) { accessToken, err := h.getAccessToken(channel) if err != nil { return nil, err diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index 02f011db1..f49dd1d65 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -268,7 +268,7 @@ func TestDescribe(t *testing.T) { s := newServer(mb) handler := &handler{handlers.NewBaseHandler(courier.ChannelType("WC"), "WeChat")} handler.Initialize(s) - logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) tcs := []struct { urn urns.URN @@ -279,7 +279,7 @@ func TestDescribe(t *testing.T) { } for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), testChannels[0], tc.urn, logger) + metadata, _ := handler.DescribeURN(context.Background(), testChannels[0], tc.urn, clog) assert.Equal(t, metadata, tc.expectedMetadata) } } diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index 0f900e765..2aa180c9d 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -172,7 +172,7 @@ type eventPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &eventPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -496,7 +496,7 @@ type mtErrorPayload struct { const maxMsgLength = 4096 // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { conn := h.Backend().RedisPool().Get() defer conn.Close() @@ -554,7 +554,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } -func buildPayloads(msg courier.Msg, h *handler, clog *courier.ChannelLogger) ([]interface{}, error) { +func buildPayloads(msg courier.Msg, h *handler, clog *courier.ChannelLog) ([]interface{}, error) { var payloads []interface{} var err error @@ -834,7 +834,7 @@ func buildPayloads(msg courier.Msg, h *handler, clog *courier.ChannelLogger) ([] } // fetchMediaID tries to fetch the id for the uploaded media, setting the result in redis. -func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string, clog *courier.ChannelLogger) (string, error) { +func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string, clog *courier.ChannelLog) (string, error) { // check in cache first rc := h.Backend().RedisPool().Get() defer rc.Close() @@ -905,7 +905,7 @@ func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string, clog return mediaID, nil } -func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload interface{}, clog *courier.ChannelLogger) (string, string, error) { +func sendWhatsAppMsg(rc redis.Conn, msg courier.Msg, sendPath *url.URL, payload interface{}, clog *courier.ChannelLog) (string, string, error) { jsonBody, err := json.Marshal(payload) if err != nil { @@ -1082,7 +1082,7 @@ type mtContactCheckPayload struct { ForceCheck bool `json:"force_check"` } -func checkWhatsAppContact(channel courier.Channel, baseURL string, urn urns.URN, clog *courier.ChannelLogger) ([]byte, error) { +func checkWhatsAppContact(channel courier.Channel, baseURL string, urn urns.URN, clog *courier.ChannelLog) ([]byte, error) { payload := mtContactCheckPayload{ Blocking: "wait", Contacts: []string{fmt.Sprintf("+%s", urn.Path())}, diff --git a/handlers/yo/yo.go b/handlers/yo/yo.go index dcca3339f..cddb0460a 100644 --- a/handlers/yo/yo.go +++ b/handlers/yo/yo.go @@ -53,7 +53,7 @@ type moForm struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { form := &moForm{} err := handlers.DecodeAndValidateForm(form, r) if err != nil { @@ -97,7 +97,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for YO channel") diff --git a/handlers/zenvia/zenvia.go b/handlers/zenvia/zenvia.go index 42fe4f95e..d6922cbc9 100644 --- a/handlers/zenvia/zenvia.go +++ b/handlers/zenvia/zenvia.go @@ -76,7 +76,7 @@ type moPayload struct { } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // get our params payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) @@ -156,7 +156,7 @@ type statusPayload struct { } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // get our params payload := &statusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) @@ -194,7 +194,7 @@ type mtPayload struct { } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { channel := msg.Channel() token := channel.StringConfigForKey(courier.ConfigAPIKey, "") diff --git a/handlers/zenviaold/zenviaold.go b/handlers/zenviaold/zenviaold.go index bc979da77..06636608f 100644 --- a/handlers/zenviaold/zenviaold.go +++ b/handlers/zenviaold/zenviaold.go @@ -115,7 +115,7 @@ var statusMapping = map[string]courier.MsgStatusValue{ } // receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // get our params payload := &moPayload{} err := handlers.DecodeAndValidateJSON(payload, r) @@ -143,7 +143,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // receiveStatus is our HTTP handler function for status updates -func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLogger) ([]courier.Event, error) { +func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // get our params payload := &statusPayload{} err := handlers.DecodeAndValidateJSON(payload, r) @@ -163,7 +163,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // Send sends the given message, logging any HTTP calls or errors -func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLogger) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") if username == "" { return nil, fmt.Errorf("no username set for ZV channel") diff --git a/server.go b/server.go index 67bf784de..61e4fe503 100644 --- a/server.go +++ b/server.go @@ -30,7 +30,7 @@ type Server interface { AddHandlerRoute(handler ChannelHandler, method string, action string, handlerFunc ChannelHandleFunc) - SendMsg(context.Context, Msg, *ChannelLogger) (MsgStatus, error) + SendMsg(context.Context, Msg, *ChannelLog) (MsgStatus, error) Backend() Backend @@ -203,7 +203,7 @@ func (s *server) Stop() error { return nil } -func (s *server) SendMsg(ctx context.Context, msg Msg, clog *ChannelLogger) (MsgStatus, error) { +func (s *server) SendMsg(ctx context.Context, msg Msg, clog *ChannelLog) (MsgStatus, error) { // find the handler for this message type handler, found := activeHandlers[msg.Channel().ChannelType()] if !found { diff --git a/test/backend.go b/test/backend.go index 546a438d1..1915b2a56 100644 --- a/test/backend.go +++ b/test/backend.go @@ -34,7 +34,7 @@ type MockBackend struct { outgoingMsgs []courier.Msg msgStatuses []courier.MsgStatus channelEvents []courier.ChannelEvent - channelLogs []*courier.ChannelLogger + channelLogs []*courier.ChannelLog lastContactName string sentMsgs map[courier.MsgID]bool seenExternalIDs []string @@ -74,9 +74,9 @@ func NewMockBackend() *MockBackend { } } -func (mb *MockBackend) ChannelLogs() []*courier.ChannelLogger { return mb.channelLogs } -func (mb *MockBackend) MsgStatuses() []courier.MsgStatus { return mb.msgStatuses } -func (mb *MockBackend) ClearMsgStatuses() { mb.msgStatuses = nil } +func (mb *MockBackend) ChannelLogs() []*courier.ChannelLog { return mb.channelLogs } +func (mb *MockBackend) MsgStatuses() []courier.MsgStatus { return mb.msgStatuses } +func (mb *MockBackend) ClearMsgStatuses() { mb.msgStatuses = nil } // GetLastQueueMsg returns the last message queued to the server func (mb *MockBackend) GetLastQueueMsg() (courier.Msg, error) { @@ -95,7 +95,7 @@ func (mb *MockBackend) GetLastChannelEvent() (courier.ChannelEvent, error) { } // GetLastChannelLog returns the last channel log written to the server -func (mb *MockBackend) GetLastChannelLog() (*courier.ChannelLogger, error) { +func (mb *MockBackend) GetLastChannelLog() (*courier.ChannelLog, error) { if len(mb.channelLogs) == 0 { return nil, errors.New("no channel logs") } @@ -182,7 +182,7 @@ func (mb *MockBackend) MarkOutgoingMsgComplete(ctx context.Context, msg courier. } // WriteChannelLog writes the passed in channel log to the DB -func (mb *MockBackend) WriteChannelLog(ctx context.Context, clog *courier.ChannelLogger) error { +func (mb *MockBackend) WriteChannelLog(ctx context.Context, clog *courier.ChannelLog) error { mb.mutex.Lock() defer mb.mutex.Unlock() From 4650ea3d913486665843aa07f9c53a1cf7ce44ba Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 24 Aug 2022 15:11:09 -0500 Subject: [PATCH 097/294] WIP --- backends/rapidpro/log.go | 2 +- handler.go | 1 + handler_test.go | 1 + handlers/base.go | 2 ++ handlers/facebookapp/facebookapp.go | 10 ++++++++-- 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/backends/rapidpro/log.go b/backends/rapidpro/log.go index a3bf81844..b78e9a739 100644 --- a/backends/rapidpro/log.go +++ b/backends/rapidpro/log.go @@ -3,7 +3,6 @@ package rapidpro import ( "context" "encoding/json" - "time" "github.com/nyaruka/courier" @@ -41,6 +40,7 @@ type channelError struct { func writeChannelLog(ctx context.Context, b *backend, clog *courier.ChannelLog) error { dbChan := clog.Channel().(*DBChannel) + // if we have an error or a non 2XX/3XX http response then this log is marked as an error isError := len(clog.Errors()) > 0 if !isError { for _, l := range clog.HTTPLogs() { diff --git a/handler.go b/handler.go index d7a600839..c1406c809 100644 --- a/handler.go +++ b/handler.go @@ -24,6 +24,7 @@ type ChannelHandler interface { ChannelType() ChannelType ChannelName() string UseChannelRouteUUID() bool + RedactValues() []string GetChannel(context.Context, *http.Request) (Channel, error) Send(context.Context, Msg, *ChannelLog) (MsgStatus, error) } diff --git a/handler_test.go b/handler_test.go index 1dc2ba44a..7484f40f7 100644 --- a/handler_test.go +++ b/handler_test.go @@ -31,6 +31,7 @@ func NewHandler() courier.ChannelHandler { func (h *dummyHandler) ChannelName() string { return "Dummy Handler" } func (h *dummyHandler) ChannelType() courier.ChannelType { return courier.ChannelType("DM") } func (h *dummyHandler) UseChannelRouteUUID() bool { return true } +func (h *dummyHandler) RedactValues() []string { return []string{"sesame"} } func (h *dummyHandler) GetChannel(ctx context.Context, r *http.Request) (courier.Channel, error) { dmChannel := test.NewMockChannel("e4bb1578-29da-4fa5-a214-9da19dd24230", "DM", "2020", "US", map[string]interface{}{}) diff --git a/handlers/base.go b/handlers/base.go index 8619db198..3d867d2d2 100644 --- a/handlers/base.go +++ b/handlers/base.go @@ -58,6 +58,8 @@ func (h *BaseHandler) UseChannelRouteUUID() bool { return h.useChannelRouteUUID } +func (h *BaseHandler) RedactValues() []string { return nil } + // GetChannel returns the channel func (h *BaseHandler) GetChannel(ctx context.Context, r *http.Request) (courier.Channel, error) { uuid, err := courier.NewChannelUUID(chi.URLParam(r, "uuid")) diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index c4228df6f..cf8bc3e94 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -29,8 +29,6 @@ var ( signatureHeader = "X-Hub-Signature" - configWACPhoneNumberID = "wac_phone_number_id" - // max for the body maxMsgLength = 1000 @@ -267,6 +265,14 @@ type moPayload struct { } `json:"entry"` } +func (h *handler) RedactValues() []string { + return []string{ + h.Server().Config().FacebookApplicationSecret, + h.Server().Config().FacebookWebhookSecret, + h.Server().Config().WhatsappAdminSystemUserToken, + } +} + // GetChannel returns the channel func (h *handler) GetChannel(ctx context.Context, r *http.Request) (courier.Channel, error) { if r.Method == http.MethodGet { From ae419081806873f113f2bc9091a3395a0f96dbd1 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 24 Aug 2022 15:31:56 -0500 Subject: [PATCH 098/294] Replace remaining usages of MakeHTTPRequest --- channel_log.go | 13 +++++----- handlers/facebook/facebook.go | 34 ++++++++++++++---------- handlers/facebookapp/facebookapp.go | 24 ++++++++--------- handlers/http.go | 16 ------------ handlers/http_test.go | 22 ---------------- handlers/viber/viber.go | 16 ++++++------ handlers/vk/vk.go | 40 ++++++++++++++--------------- 7 files changed, 68 insertions(+), 97 deletions(-) diff --git a/channel_log.go b/channel_log.go index 8b83fcebc..ed3efa011 100644 --- a/channel_log.go +++ b/channel_log.go @@ -11,12 +11,13 @@ import ( type ChannelLogType string const ( - ChannelLogTypeUnknown ChannelLogType = "unknown" - ChannelLogTypeMsgSend ChannelLogType = "msg_send" - ChannelLogTypeMsgStatus ChannelLogType = "msg_status" - ChannelLogTypeMsgReceive ChannelLogType = "msg_receive" - ChannelLogTypeEventReceive ChannelLogType = "event_receive" - ChannelLogTypeTokenFetch ChannelLogType = "token_fetch" + ChannelLogTypeUnknown ChannelLogType = "unknown" + ChannelLogTypeMsgSend ChannelLogType = "msg_send" + ChannelLogTypeMsgStatus ChannelLogType = "msg_status" + ChannelLogTypeMsgReceive ChannelLogType = "msg_receive" + ChannelLogTypeEventReceive ChannelLogType = "event_receive" + ChannelLogTypeTokenFetch ChannelLogType = "token_fetch" + ChannelLogTypePageSubscribe ChannelLogType = "page_subscribe" ) type ChannelError struct { diff --git a/handlers/facebook/facebook.go b/handlers/facebook/facebook.go index 446ba6ec7..7118a92c5 100644 --- a/handlers/facebook/facebook.go +++ b/handlers/facebook/facebook.go @@ -102,19 +102,7 @@ func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w // wait a bit for Facebook to handle this response time.Sleep(subscribeTimeout) - // subscribe to messaging events for this page - form := url.Values{} - form.Set("access_token", authToken) - req, _ := http.NewRequest(http.MethodPost, subscribeURL, strings.NewReader(form.Encode())) - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - - trace, err := handlers.MakeHTTPRequest(req) - - // log if we get any kind of error - success, _ := jsonparser.GetBoolean(trace.ResponseBody, "success") - if err != nil || !success { - logrus.WithField("channel_uuid", channel.UUID()).Error("error subscribing to Facebook page events") - } + h.subscribeToEvents(ctx, channel, authToken) }() // and respond with the challenge token @@ -122,6 +110,26 @@ func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w return nil, err } +func (h *handler) subscribeToEvents(ctx context.Context, channel courier.Channel, authToken string) { + clog := courier.NewChannelLog(courier.ChannelLogTypePageSubscribe, channel) + + // subscribe to messaging events for this page + form := url.Values{} + form.Set("access_token", authToken) + req, _ := http.NewRequest(http.MethodPost, subscribeURL, strings.NewReader(form.Encode())) + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + resp, respBody, err := handlers.RequestHTTP(req, clog) + + // log if we get any kind of error + success, _ := jsonparser.GetBoolean(respBody, "success") + if err != nil || resp.StatusCode/100 != 2 || !success { + logrus.WithField("channel_uuid", channel.UUID()).Error("error subscribing to Facebook page events") + } + + h.Backend().WriteChannelLog(ctx, clog) +} + type fbUser struct { ID string `json:"id"` } diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index c4228df6f..871923711 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -330,7 +330,7 @@ func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w return nil, err } -func resolveMediaURL(mediaID string, token string) (string, error) { +func resolveMediaURL(mediaID string, token string, clog *courier.ChannelLog) (string, error) { if token == "" { return "", fmt.Errorf("missing token for WA channel") } @@ -344,12 +344,12 @@ func resolveMediaURL(mediaID string, token string) (string, error) { //req.Header.Set("User-Agent", utils.HTTPUserAgent) req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - return "", err + resp, respBody, err := handlers.RequestHTTP(req, clog) + if err != nil || resp.StatusCode/100 != 2 { + return "", errors.New("error resolving media URL") } - mediaURL, err := jsonparser.GetString(trace.ResponseBody, "url") + mediaURL, err := jsonparser.GetString(respBody, "url") return mediaURL, err } @@ -382,7 +382,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h if channel.ChannelType() == "FBA" || channel.ChannelType() == "IG" { events, data, err = h.processFacebookInstagramPayload(ctx, channel, payload, w, r) } else { - events, data, err = h.processCloudWhatsAppPayload(ctx, channel, payload, w, r) + events, data, err = h.processCloudWhatsAppPayload(ctx, channel, payload, w, r, clog) } @@ -393,7 +393,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return events, courier.WriteDataResponse(ctx, w, http.StatusOK, "Events Handled", data) } -func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel courier.Channel, payload *moPayload, w http.ResponseWriter, r *http.Request) ([]courier.Event, []interface{}, error) { +func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel courier.Channel, payload *moPayload, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, []interface{}, error) { // the list of events we deal with events := make([]courier.Event, 0, 2) @@ -436,21 +436,21 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri text = msg.Text.Body } else if msg.Type == "audio" && msg.Audio != nil { text = msg.Audio.Caption - mediaURL, err = resolveMediaURL(msg.Audio.ID, token) + mediaURL, err = resolveMediaURL(msg.Audio.ID, token, clog) } else if msg.Type == "voice" && msg.Voice != nil { text = msg.Voice.Caption - mediaURL, err = resolveMediaURL(msg.Voice.ID, token) + mediaURL, err = resolveMediaURL(msg.Voice.ID, token, clog) } else if msg.Type == "button" && msg.Button != nil { text = msg.Button.Text } else if msg.Type == "document" && msg.Document != nil { text = msg.Document.Caption - mediaURL, err = resolveMediaURL(msg.Document.ID, token) + mediaURL, err = resolveMediaURL(msg.Document.ID, token, clog) } else if msg.Type == "image" && msg.Image != nil { text = msg.Image.Caption - mediaURL, err = resolveMediaURL(msg.Image.ID, token) + mediaURL, err = resolveMediaURL(msg.Image.ID, token, clog) } else if msg.Type == "video" && msg.Video != nil { text = msg.Video.Caption - mediaURL, err = resolveMediaURL(msg.Video.ID, token) + mediaURL, err = resolveMediaURL(msg.Video.ID, token, clog) } else if msg.Type == "location" && msg.Location != nil { mediaURL = fmt.Sprintf("geo:%f,%f", msg.Location.Latitude, msg.Location.Longitude) } else if msg.Type == "interactive" && msg.Interactive.Type == "button_reply" { diff --git a/handlers/http.go b/handlers/http.go index 31e988a3a..0aed1a72c 100644 --- a/handlers/http.go +++ b/handlers/http.go @@ -1,7 +1,6 @@ package handlers import ( - "fmt" "net/http" "github.com/nyaruka/courier" @@ -37,18 +36,3 @@ func RequestHTTPWithClient(client *http.Client, req *http.Request, clog *courier return resp, body, nil } - -// Deprecated: use RequestHTTP instead -func MakeHTTPRequest(req *http.Request) (*httpx.Trace, error) { - trace, err := httpx.DoTrace(utils.GetHTTPClient(), req, nil, nil, 0) - if err != nil { - return trace, err - } - - // return an error if we got a non-200 status - if trace.Response != nil && trace.Response.StatusCode/100 != 2 { - return trace, fmt.Errorf("received non 200 status: %d", trace.Response.StatusCode) - } - - return trace, nil -} diff --git a/handlers/http_test.go b/handlers/http_test.go index 4e24550b0..6de7829c9 100644 --- a/handlers/http_test.go +++ b/handlers/http_test.go @@ -47,25 +47,3 @@ func TestDoHTTPRequest(t *testing.T) { assert.Equal(t, 400, hlog2.StatusCode) assert.Equal(t, "https://api.messages.com/send.json", hlog2.URL) } - -func TestMakeHTTPRequest(t *testing.T) { - httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ - "https://api.messages.com/send.json": { - httpx.NewMockResponse(200, nil, []byte(`{"status":"success"}`)), - httpx.NewMockResponse(400, nil, []byte(`{"status":"error"}`)), - }, - })) - defer httpx.SetRequestor(httpx.DefaultRequestor) - - req, _ := http.NewRequest("POST", "https://api.messages.com/send.json", nil) - trace, err := handlers.MakeHTTPRequest(req) - assert.NoError(t, err) - assert.Equal(t, 200, trace.Response.StatusCode) - assert.Equal(t, []byte(`{"status":"success"}`), trace.ResponseBody) - - req, _ = http.NewRequest("POST", "https://api.messages.com/send.json", nil) - trace, err = handlers.MakeHTTPRequest(req) - assert.EqualError(t, err, "received non 200 status: 400") - assert.Equal(t, 400, trace.Response.StatusCode) - assert.Equal(t, []byte(`{"status":"error"}`), trace.ResponseBody) -} diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index 40bc5350a..f1ddfbab7 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -358,7 +358,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann case "video": msgType = "video" attURL = mediaURL - attSize, err = getAttachmentSize(mediaURL) + attSize, err = getAttachmentSize(mediaURL, clog) if err != nil { return nil, err } @@ -367,7 +367,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann case "audio": msgType = "file" attURL = mediaURL - attSize, err = getAttachmentSize(mediaURL) + attSize, err = getAttachmentSize(mediaURL, clog) if err != nil { return nil, err } @@ -431,20 +431,20 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } -func getAttachmentSize(u string) (int, error) { +func getAttachmentSize(u string, clog *courier.ChannelLog) (int, error) { req, err := http.NewRequest(http.MethodHead, u, nil) if err != nil { return 0, err } - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - return 0, err + resp, _, err := handlers.RequestHTTP(req, clog) + if err != nil || resp.StatusCode/100 != 2 { + return 0, errors.New("unable to get attachment size") } - contentLenHdr := trace.Response.Header.Get("Content-Length") + contentLenHdr := resp.Header.Get("Content-Length") - if trace.Response.Header.Get("Content-Length") != "" { + if resp.Header.Get("Content-Length") != "" { contentLength, err := strconv.Atoi(contentLenHdr) if err == nil { return contentLength, nil diff --git a/handlers/vk/vk.go b/handlers/vk/vk.go index 94173a525..9e8cd9f6c 100644 --- a/handlers/vk/vk.go +++ b/handlers/vk/vk.go @@ -446,7 +446,7 @@ func buildTextAndAttachmentParams(msg courier.Msg, clog *courier.ChannelLog) (st switch mediaType { case mediaTypeImage: - if attachment, err := handleMediaUploadAndGetAttachment(msg.Channel(), mediaTypeImage, mediaExt, mediaURL); err == nil { + if attachment, err := handleMediaUploadAndGetAttachment(msg.Channel(), mediaTypeImage, mediaExt, mediaURL, clog); err == nil { msgAttachments = append(msgAttachments, attachment) } else { clog.Error(err) @@ -461,14 +461,14 @@ func buildTextAndAttachmentParams(msg courier.Msg, clog *courier.ChannelLog) (st } // handleMediaUploadAndGetAttachment handles media downloading, uploading, saving information and returns the attachment string -func handleMediaUploadAndGetAttachment(channel courier.Channel, mediaType, mediaExt, mediaURL string) (string, error) { +func handleMediaUploadAndGetAttachment(channel courier.Channel, mediaType, mediaExt, mediaURL string, clog *courier.ChannelLog) (string, error) { switch mediaType { case mediaTypeImage: uploadKey := "photo" // initialize server URL to upload photos if URLPhotoUploadServer == "" { - if serverURL, err := getUploadServerURL(channel, apiBaseURL+actionGetPhotoUploadServer); err == nil { + if serverURL, err := getUploadServerURL(channel, apiBaseURL+actionGetPhotoUploadServer, clog); err == nil { URLPhotoUploadServer = serverURL } } @@ -477,7 +477,7 @@ func handleMediaUploadAndGetAttachment(channel courier.Channel, mediaType, media if err != nil { return "", err } - uploadResponse, err := uploadMedia(URLPhotoUploadServer, uploadKey, mediaExt, download) + uploadResponse, err := uploadMedia(URLPhotoUploadServer, uploadKey, mediaExt, download, clog) if err != nil { return "", err @@ -488,7 +488,7 @@ func handleMediaUploadAndGetAttachment(channel courier.Channel, mediaType, media return "", err } serverId := strconv.FormatInt(payload.ServerId, 10) - info, err := saveUploadedMediaInfo(channel, apiBaseURL+actionSaveUploadedPhotoInfo, serverId, payload.Hash, uploadKey, payload.Photo) + info, err := saveUploadedMediaInfo(channel, apiBaseURL+actionSaveUploadedPhotoInfo, serverId, payload.Hash, uploadKey, payload.Photo, clog) if err != nil { return "", err @@ -503,7 +503,7 @@ func handleMediaUploadAndGetAttachment(channel courier.Channel, mediaType, media } // getUploadServerURL gets VK's media upload server -func getUploadServerURL(channel courier.Channel, sendURL string) (string, error) { +func getUploadServerURL(channel courier.Channel, sendURL string, clog *courier.ChannelLog) (string, error) { req, err := http.NewRequest(http.MethodPost, sendURL, nil) if err != nil { @@ -512,14 +512,14 @@ func getUploadServerURL(channel courier.Channel, sendURL string) (string, error) params := buildApiBaseParams(channel) req.URL.RawQuery = params.Encode() - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - return "", err + resp, respBody, err := handlers.RequestHTTP(req, clog) + if err != nil || resp.StatusCode/100 != 2 { + return "", errors.New("unable to get upload server URL") } uploadServer := &uploadServerPayload{} - if err = json.Unmarshal(trace.ResponseBody, uploadServer); err != nil { + if err = json.Unmarshal(respBody, uploadServer); err != nil { return "", nil } return uploadServer.Server.UploadURL, nil @@ -540,7 +540,7 @@ func downloadMedia(mediaURL string) (io.Reader, error) { } // uploadMedia multiform request that passes file key as uploadKey and file value as media to upload server -func uploadMedia(serverURL, uploadKey, mediaExt string, media io.Reader) ([]byte, error) { +func uploadMedia(serverURL, uploadKey, mediaExt string, media io.Reader, clog *courier.ChannelLog) ([]byte, error) { body := &bytes.Buffer{} writer := multipart.NewWriter(body) fileName := fmt.Sprintf("%s.%s", uploadKey, mediaExt) @@ -567,15 +567,15 @@ func uploadMedia(serverURL, uploadKey, mediaExt string, media io.Reader) ([]byte req.Header.Set("Content-Type", writer.FormDataContentType()) - if trace, err := handlers.MakeHTTPRequest(req); err != nil { - return nil, err - } else { - return trace.ResponseBody, nil + resp, respBody, err := handlers.RequestHTTP(req, clog) + if err != nil || resp.StatusCode/100 != 2 { + return nil, errors.New("unable to upload media") } + return respBody, nil } // saveUploadedMediaInfo saves uploaded media info and returns an object containing media/owner id -func saveUploadedMediaInfo(channel courier.Channel, sendURL, serverId, hash, mediaKey, mediaValue string) (*mediaUploadInfoPayload, error) { +func saveUploadedMediaInfo(channel courier.Channel, sendURL, serverId, hash, mediaKey, mediaValue string, clog *courier.ChannelLog) (*mediaUploadInfoPayload, error) { params := buildApiBaseParams(channel) params.Set(paramServerId, serverId) params.Set(paramHash, hash) @@ -588,9 +588,9 @@ func saveUploadedMediaInfo(channel courier.Channel, sendURL, serverId, hash, med req.URL.RawQuery = params.Encode() - trace, err := handlers.MakeHTTPRequest(req) - if err != nil { - return nil, err + resp, respBody, err := handlers.RequestHTTP(req, clog) + if err != nil || resp.StatusCode/100 != 2 { + return nil, errors.New("unable to save uploaded media info") } // parsing response @@ -600,7 +600,7 @@ func saveUploadedMediaInfo(channel courier.Channel, sendURL, serverId, hash, med medias := &responsePayload{} // try get first object - if err = json.Unmarshal(trace.ResponseBody, medias); err != nil || len(medias.Response) == 0 { + if err = json.Unmarshal(respBody, medias); err != nil || len(medias.Response) == 0 { return nil, errors.New("no response") } else { return &medias.Response[0], nil From 52c0edc59bbaf0787a32b18a9af4796f56177feb Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 25 Aug 2022 10:17:49 -0500 Subject: [PATCH 099/294] Handler tests should check for channel logs --- handlers/bongolive/bongolive_test.go | 73 ++++++++++++++++++------ handlers/facebook/facebook_test.go | 20 +++---- handlers/facebookapp/facebookapp_test.go | 34 +++++------ handlers/freshchat/freshchat_test.go | 65 ++++++++++++--------- handlers/jiochat/jiochat_test.go | 2 +- handlers/mtarget/mtarget_test.go | 2 +- handlers/novo/novo_test.go | 36 ++++++++---- handlers/telegram/telegram_test.go | 2 +- handlers/test.go | 23 ++++---- handlers/viber/viber_test.go | 2 +- handlers/wechat/wechat_test.go | 2 +- test/backend.go | 33 +++++------ 12 files changed, 178 insertions(+), 116 deletions(-) diff --git a/handlers/bongolive/bongolive_test.go b/handlers/bongolive/bongolive_test.go index 6cb0c39c3..1eea920cf 100644 --- a/handlers/bongolive/bongolive_test.go +++ b/handlers/bongolive/bongolive_test.go @@ -13,29 +13,64 @@ var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "BL", "2020", "KE", nil), } -var ( +const ( receiveURL = "/c/bl/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" - - validReceive = "msgtype=1&id=12345678&message=Msg&sourceaddr=254791541111" - validReceiveNoMsgType = "id=12345678&message=Msg&sourceaddr=254791541111" - missingNumber = "msgtype=1&id=12345679&message=Msg" - - validStatus = "msgtype=5&dlrid=12345&status=1" - invalidStatus = "msgtype=5&dlrid=12345&status=12" - - invalidMsgType = "msgtype=3&id=12345&status=1" ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111")}, - {Label: "Receive Valid", URL: receiveURL, Data: validReceiveNoMsgType, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111")}, - {Label: "Receive Missing Number", URL: receiveURL, Data: missingNumber, ExpectedStatus: 400, ExpectedResponse: ""}, - {Label: "Status No params", URL: receiveURL, Data: "", ExpectedStatus: 405, ExpectedResponse: ""}, - {Label: "Status invalid params", URL: receiveURL, Data: invalidStatus, ExpectedStatus: 400, ExpectedResponse: ""}, - {Label: "Status valid", URL: receiveURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: ""}, - {Label: "Invalid Msg Type", URL: receiveURL, Data: invalidMsgType, ExpectedStatus: 400, ExpectedResponse: ""}, + { + Label: "Receive Valid", + URL: receiveURL, + Data: "msgtype=1&id=12345678&message=Msg&sourceaddr=254791541111", + ExpectedStatus: 200, + ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: Sp("tel:+254791541111"), + }, + { + Label: "Receive Valid", + URL: receiveURL, + Data: "id=12345678&message=Msg&sourceaddr=254791541111", + ExpectedStatus: 200, + ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: Sp("tel:+254791541111"), + }, + { + Label: "Receive Missing Number", + URL: receiveURL, + Data: "msgtype=1&id=12345679&message=Msg", + ExpectedStatus: 400, + ExpectedResponse: "", + }, + { + Label: "Status No params", + URL: receiveURL, + Data: "", + ExpectedStatus: 405, + ExpectedResponse: "", + }, + { + Label: "Status invalid params", + URL: receiveURL, + Data: "msgtype=5&dlrid=12345&status=12", + ExpectedStatus: 400, + ExpectedResponse: "", + }, + { + Label: "Status valid", + URL: receiveURL, + Data: "msgtype=5&dlrid=12345&status=1", + ExpectedStatus: 200, + ExpectedResponse: "", + }, + { + Label: "Invalid Msg Type", + URL: receiveURL, + Data: "msgtype=3&id=12345&status=1", + ExpectedStatus: 400, + ExpectedResponse: "", + }, } func TestHandler(t *testing.T) { diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index 60174839d..cc9ed5c28 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -432,24 +432,24 @@ var testCases = []ChannelHandleTestCase{ {Label: "Receive OptIn UserRef", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: optInUserRef, ExpectedStatus: 200, ExpectedResponse: "Handled", ExpectedURN: Sp("facebook:ref:optin_user_ref"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}}, + ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}}, {Label: "Receive OptIn", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: optIn, ExpectedStatus: 200, ExpectedResponse: "Handled", ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}}, + ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}}, {Label: "Receive Get Started", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: postbackGetStarted, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.NewConversation), - ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}}, + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.NewConversation, + ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}}, {Label: "Receive Referral Postback", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: postback, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.Referral), - ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}}, + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, + ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}}, {Label: "Receive Referral", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: postbackReferral, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.Referral), - ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}}, + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, + ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}}, {Label: "Receive Referral", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: referral, ExpectedStatus: 200, ExpectedResponse: `"referrer_id":"referral id"`, - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.Referral), - ChannelEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}}, + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, + ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}}, {Label: "Receive DLR", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: dlr, ExpectedStatus: 200, ExpectedResponse: "Handled", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedMsgStatus: Sp(courier.MsgDelivered), ExpectedExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233")}, diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 8b8f530f8..2657f0a30 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -53,30 +53,30 @@ var testCasesFBA = []ChannelHandleTestCase{ {Label: "Receive OptIn UserRef", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/optInUserRef.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", ExpectedURN: Sp("facebook:ref:optin_user_ref"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, + ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, PrepRequest: addValidSignature}, {Label: "Receive OptIn", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/optIn.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ChannelEvent: Sp(courier.Referral), ChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, + ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, PrepRequest: addValidSignature}, {Label: "Receive Get Started", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postbackGetStarted.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.NewConversation), - ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, - PrepRequest: addValidSignature}, + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.NewConversation, + ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, + PrepRequest: addValidSignature}, {Label: "Receive Referral Postback", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postback.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.Referral), - ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, - PrepRequest: addValidSignature}, + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, + ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, + PrepRequest: addValidSignature}, {Label: "Receive Referral", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postbackReferral.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.Referral), - ChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, - PrepRequest: addValidSignature}, + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, + ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, + PrepRequest: addValidSignature}, {Label: "Receive Referral", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/referral.json")), ExpectedStatus: 200, ExpectedResponse: `"referrer_id":"referral id"`, - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.Referral), - ChannelEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, - PrepRequest: addValidSignature}, + ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, + ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, + PrepRequest: addValidSignature}, {Label: "Receive DLR", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/dlr.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedMsgStatus: Sp(courier.MsgDelivered), ExpectedExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233"), @@ -111,9 +111,9 @@ var testCasesIG = []ChannelHandleTestCase{ PrepRequest: addValidSignature}, {Label: "Receive Icebreaker Get Started", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/icebreakerGetStarted.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("instagram:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ChannelEvent: Sp(courier.NewConversation), - ChannelEventExtra: map[string]interface{}{"title": "icebreaker question", "payload": "get_started"}, - PrepRequest: addValidSignature}, + ExpectedURN: Sp("instagram:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.NewConversation, + ExpectedChannelEventExtra: map[string]interface{}{"title": "icebreaker question", "payload": "get_started"}, + PrepRequest: addValidSignature}, {Label: "Different Page", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/differentPageIG.json")), ExpectedStatus: 200, ExpectedResponse: `"data":[]`, PrepRequest: addValidSignature}, {Label: "Echo", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/echoIG.json")), ExpectedStatus: 200, ExpectedResponse: `ignoring echo`, PrepRequest: addValidSignature}, {Label: "No Entries", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/noEntriesIG.json")), ExpectedStatus: 400, ExpectedResponse: "no entries found", PrepRequest: addValidSignature}, diff --git a/handlers/freshchat/freshchat_test.go b/handlers/freshchat/freshchat_test.go index 11926f535..7e5deabe9 100644 --- a/handlers/freshchat/freshchat_test.go +++ b/handlers/freshchat/freshchat_test.go @@ -30,34 +30,47 @@ var ( ) var sigtestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid w Signature", - Headers: map[string]string{ - "Content-Type": "application/json", - "X-FreshChat-Signature": validSignature}, - URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Test 2"), ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC)}, - - {Label: "Bad Signature", - Headers: map[string]string{ - "Content-Type": "application/json", - "X-FreshChat-Signature": invalidSignature}, - URL: receiveURL, Data: validReceive, ExpectedStatus: 400, ExpectedResponse: `{"message":"Error","data":[{"type":"error","error":"unable to verify signature, crypto/rsa: verification error"}]}`, - ExpectedMsgText: Sp("Test 2"), ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC)}, + { + Label: "Receive Valid w Signature", + Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": validSignature}, + URL: receiveURL, + Data: validReceive, + ExpectedStatus: 200, + ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Test 2"), + ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), + ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC), + }, + { + Label: "Bad Signature", + Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": invalidSignature}, + URL: receiveURL, + Data: validReceive, + ExpectedStatus: 400, + ExpectedResponse: `{"message":"Error","data":[{"type":"error","error":"unable to verify signature, crypto/rsa: verification error"}]}`, + }, } -var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid w Sig", - Headers: map[string]string{ - "Content-Type": "application/json", - "X-FreshChat-Signature": validSignature}, - URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Test 2"), ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC)}, - {Label: "Bad JSON", - Headers: map[string]string{ - "Content-Type": "application/json", - "X-FreshChat-Signature": invalidSignature}, - URL: receiveURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: `{"message":"Error","data":[{"type":"error","error":"unable to parse request JSON: invalid character 'e' looking for beginning of value"}]}`, - ExpectedMsgText: Sp("Test 2"), ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC)}, +var testCases = []ChannelHandleTestCase{ + { + Label: "Receive Valid w Sig", + Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": validSignature}, + URL: receiveURL, + Data: validReceive, + ExpectedStatus: 200, + ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Test 2"), + ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), + ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC), + }, + { + Label: "Bad JSON", + Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": invalidSignature}, + URL: receiveURL, + Data: notJSON, + ExpectedStatus: 400, + ExpectedResponse: `{"message":"Error","data":[{"type":"error","error":"unable to parse request JSON: invalid character 'e' looking for beginning of value"}]}`, + }, } func TestHandler(t *testing.T) { diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index b8aee0466..522f47826 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -160,7 +160,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedStatus: 200, ExpectedResponse: "Event Accepted", - ChannelEvent: Sp(courier.NewConversation), ExpectedURN: Sp("jiochat:1234")}, + ExpectedChannelEvent: courier.NewConversation, ExpectedURN: Sp("jiochat:1234")}, {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, ExpectedStatus: 200, ExpectedResponse: "unknown event"}, diff --git a/handlers/mtarget/mtarget_test.go b/handlers/mtarget/mtarget_test.go index 73ffac3ef..83052878f 100644 --- a/handlers/mtarget/mtarget_test.go +++ b/handlers/mtarget/mtarget_test.go @@ -36,7 +36,7 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+923161909799")}, {Label: "Invalid URN", URL: receiveURL, Data: receiveInvalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Receive Stop", URL: receiveURL, Data: receiveStop, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedURN: Sp("tel:+923161909799"), ChannelEvent: Sp("stop_contact")}, + ExpectedURN: Sp("tel:+923161909799"), ExpectedChannelEvent: courier.StopContact}, {Label: "Receive Missing From", URL: receiveURL, Data: receiveMissingFrom, ExpectedStatus: 400, ExpectedResponse: "missing required field 'Msisdn'"}, {Label: "Receive Part 2", URL: receiveURL, Data: receivePart2, ExpectedStatus: 200, ExpectedResponse: "received"}, diff --git a/handlers/novo/novo_test.go b/handlers/novo/novo_test.go index c87db82f0..9e72ef668 100644 --- a/handlers/novo/novo_test.go +++ b/handlers/novo/novo_test.go @@ -17,20 +17,36 @@ var testChannels = []courier.Channel{ }), } -var ( +const ( receiveURL = "/c/nv/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" - - validReceive = "text=Msg&from=18686846481" - missingNumber = "text=Msg" ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+18686846481"), Headers: map[string]string{"Authorization": "sesame"}}, - {Label: "Receive Missing Number", URL: receiveURL, Data: missingNumber, ExpectedStatus: 400, ExpectedResponse: "required field 'from'", - Headers: map[string]string{"Authorization": "sesame"}}, - {Label: "Receive Missing Authorization", URL: receiveURL, Data: validReceive, ExpectedStatus: 401, ExpectedResponse: "invalid Authorization header", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+18686846481")}, + { + Label: "Receive Valid", + URL: receiveURL, + Headers: map[string]string{"Authorization": "sesame"}, + Data: "text=Msg&from=18686846481", + ExpectedStatus: 200, + ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: Sp("tel:+18686846481"), + }, + { + Label: "Receive Missing Number", + URL: receiveURL, + Headers: map[string]string{"Authorization": "sesame"}, + Data: "text=Msg", + ExpectedStatus: 400, + ExpectedResponse: "required field 'from'", + }, + { + Label: "Receive Missing Authorization", + URL: receiveURL, + Data: "text=Msg&from=18686846481", + ExpectedStatus: 401, + ExpectedResponse: "invalid Authorization header", + }, } func TestHandler(t *testing.T) { diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index de54e727c..0bb9958cc 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -456,7 +456,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Start Message", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: startMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ChannelEvent: Sp(string(courier.NewConversation)), ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedChannelEvent: courier.NewConversation, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive No Params", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: emptyMsg, ExpectedStatus: 200, ExpectedResponse: "Ignoring"}, diff --git a/handlers/test.go b/handlers/test.go index 7a90f4c9e..bb5f22acb 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -49,8 +49,8 @@ type ChannelHandleTestCase struct { ExpectedExternalID *string ExpectedMsgID int64 - ChannelEvent *string - ChannelEventExtra map[string]interface{} + ExpectedChannelEvent courier.ChannelEventType + ExpectedChannelEventExtra map[string]interface{} NoQueueErrorCheck bool NoInvalidChannelCheck bool @@ -353,8 +353,7 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri t.Run(tc.Label, func(t *testing.T) { require := require.New(t) - mb.ClearQueueMsgs() - mb.ClearSeenExternalIDs() + mb.Reset() testHandlerRequest(t, s, tc.URL, tc.Headers, tc.Data, tc.MultipartFormFields, tc.ExpectedStatus, &tc.ExpectedResponse, tc.PrepRequest) @@ -373,11 +372,11 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri require.Equal(mb.LenQueuedMsgs(), 1) require.Equal(*tc.ExpectedMsgText, msg.Text()) } - if tc.ChannelEvent != nil { - require.Equal(*tc.ChannelEvent, string(event.EventType())) + if tc.ExpectedChannelEvent != "" { + assert.Equal(t, tc.ExpectedChannelEvent, event.EventType()) } - if tc.ChannelEventExtra != nil { - require.Equal(tc.ChannelEventExtra, event.Extra()) + if tc.ExpectedChannelEventExtra != nil { + require.Equal(tc.ExpectedChannelEventExtra, event.Extra()) } if tc.ExpectedURN != nil { if msg != nil { @@ -426,6 +425,11 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri } } } + + // if we're expecting a message, status or event, check we have a log for it + if tc.ExpectedMsgText != nil || tc.ExpectedMsgStatus != nil || tc.ExpectedChannelEvent != "" { + assert.Greater(t, len(mb.ChannelLogs()), 0, "expected at least one channel log") + } }) } @@ -459,8 +463,7 @@ func RunChannelBenchmarks(b *testing.B, channels []courier.Channel, handler cour handler.Initialize(s) for _, testCase := range testCases { - mb.ClearQueueMsgs() - mb.ClearSeenExternalIDs() + mb.Reset() b.Run(testCase.Label, func(b *testing.B) { for i := 0; i < b.N; i++ { diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index 821c1b917..407beab63 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -497,7 +497,7 @@ var testCases = []ChannelHandleTestCase{ {Label: "Delivered Status Report", URL: receiveURL, Data: deliveredStatusReport, ExpectedStatus: 200, ExpectedResponse: `Ignored`, PrepRequest: addValidSignature}, {Label: "Subcribe", URL: receiveURL, Data: validSubscribed, ExpectedStatus: 200, ExpectedResponse: "Accepted", PrepRequest: addValidSignature}, {Label: "Subcribe Invalid URN", URL: receiveURL, Data: invalidURNSubscribed, ExpectedStatus: 400, ExpectedResponse: "invalid viber id", PrepRequest: addValidSignature}, - {Label: "Unsubcribe", URL: receiveURL, Data: validUnsubscribed, ExpectedStatus: 200, ExpectedResponse: "Accepted", ChannelEvent: Sp(string(courier.StopContact)), PrepRequest: addValidSignature}, + {Label: "Unsubcribe", URL: receiveURL, Data: validUnsubscribed, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedChannelEvent: courier.StopContact, PrepRequest: addValidSignature}, {Label: "Unsubcribe Invalid URN", URL: receiveURL, Data: invalidURNUnsubscribed, ExpectedStatus: 400, ExpectedResponse: "invalid viber id", PrepRequest: addValidSignature}, {Label: "Conversation Started", URL: receiveURL, Data: validConversationStarted, ExpectedStatus: 200, ExpectedResponse: "ignored conversation start", PrepRequest: addValidSignature}, {Label: "Unexpected event", URL: receiveURL, Data: unexpectedEvent, ExpectedStatus: 400, diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index f49dd1d65..7e6d992be 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -156,7 +156,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedStatus: 200, ExpectedResponse: "Event Accepted", - ChannelEvent: Sp(courier.NewConversation), ExpectedURN: Sp("wechat:1234")}, + ExpectedChannelEvent: courier.NewConversation, ExpectedURN: Sp("wechat:1234")}, {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, ExpectedStatus: 200, ExpectedResponse: "unknown event"}, diff --git a/test/backend.go b/test/backend.go index 1915b2a56..e2621ac70 100644 --- a/test/backend.go +++ b/test/backend.go @@ -25,16 +25,18 @@ type MockBackend struct { channelsByAddress map[courier.ChannelAddress]courier.Channel contacts map[urns.URN]courier.Contact media map[string]courier.Media // url -> Media - queueMsgs []courier.Msg errorOnQueue bool mutex sync.RWMutex redisPool *redis.Pool + lastMsgID courier.MsgID + + queueMsgs []courier.Msg + outgoingMsgs []courier.Msg + msgStatuses []courier.MsgStatus + channelEvents []courier.ChannelEvent + channelLogs []*courier.ChannelLog - outgoingMsgs []courier.Msg - msgStatuses []courier.MsgStatus - channelEvents []courier.ChannelEvent - channelLogs []*courier.ChannelLog lastContactName string sentMsgs map[courier.MsgID]bool seenExternalIDs []string @@ -94,14 +96,6 @@ func (mb *MockBackend) GetLastChannelEvent() (courier.ChannelEvent, error) { return mb.channelEvents[len(mb.channelEvents)-1], nil } -// GetLastChannelLog returns the last channel log written to the server -func (mb *MockBackend) GetLastChannelLog() (*courier.ChannelLog, error) { - if len(mb.channelLogs) == 0 { - return nil, errors.New("no channel logs") - } - return mb.channelLogs[len(mb.channelLogs)-1], nil -} - // GetLastMsgStatus returns the last status written to the server func (mb *MockBackend) GetLastMsgStatus() (courier.MsgStatus, error) { if len(mb.msgStatuses) == 0 { @@ -204,6 +198,9 @@ func (mb *MockBackend) WriteMsg(ctx context.Context, m courier.Msg) error { return nil } + mb.lastMsgID++ + mock.id = mb.lastMsgID + if mb.errorOnQueue { return errors.New("unable to queue message") } @@ -326,14 +323,12 @@ func (mb *MockBackend) Stop() error { return nil } // Cleanup cleans up any connections that are open func (mb *MockBackend) Cleanup() error { return nil } -// ClearQueueMsgs clears our mock msg queue -func (mb *MockBackend) ClearQueueMsgs() { +// Reset clears our queued messages, seen external IDs, and channel logs +func (mb *MockBackend) Reset() { + mb.lastMsgID = courier.NilMsgID mb.queueMsgs = nil -} - -// ClearSeenExternalIDs clears our mock seen external ids -func (mb *MockBackend) ClearSeenExternalIDs() { mb.seenExternalIDs = nil + mb.channelLogs = nil } // LenQueuedMsgs Get the length of queued msgs From ba96f5e2f0fd6617e6ce4cf5eb524c8be2a3b82c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 25 Aug 2022 10:36:23 -0500 Subject: [PATCH 100/294] Update CHANGELOG.md for v7.5.16 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf8527737..6664f883d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.16 +---------- + * Write channel logs in new format + v7.5.15 ---------- * Use logger for handler func calls From 2c871ad2af10eebed1cd704843cd748b9bf1ea3c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 25 Aug 2022 10:54:27 -0500 Subject: [PATCH 101/294] Fix writing channel logs --- backends/rapidpro/log.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/rapidpro/log.go b/backends/rapidpro/log.go index a3bf81844..01924a23d 100644 --- a/backends/rapidpro/log.go +++ b/backends/rapidpro/log.go @@ -21,7 +21,7 @@ type ChannelLog struct { ChannelID courier.ChannelID `db:"channel_id"` MsgID courier.MsgID `db:"msg_id"` HTTPLogs json.RawMessage `db:"http_logs"` - Errors json.RawMessage `db:"http_logs"` + Errors json.RawMessage `db:"errors"` IsError bool `db:"is_error"` CreatedOn time.Time `db:"created_on"` ElapsedMS int `db:"elapsed_ms"` From 60dad1dd49cdd1f12baf9f727c7d83ad42643d79 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 25 Aug 2022 10:54:50 -0500 Subject: [PATCH 102/294] Update CHANGELOG.md for v7.5.17 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6664f883d..2bd90038a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.17 +---------- + * Fix writing channel logs + v7.5.16 ---------- * Write channel logs in new format From ec7565e847d82452345f968d2524021d9cf9d829 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 25 Aug 2022 12:17:09 -0500 Subject: [PATCH 103/294] Add UUID to channel logs --- channel_log.go | 32 +++++++++++++++++++++++++++----- channel_log_test.go | 13 +++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/channel_log.go b/channel_log.go index 8b83fcebc..62512a563 100644 --- a/channel_log.go +++ b/channel_log.go @@ -5,6 +5,7 @@ import ( "github.com/nyaruka/gocommon/dates" "github.com/nyaruka/gocommon/httpx" + "github.com/nyaruka/gocommon/uuids" ) // ChannelLogType is the type of channel interaction we are logging @@ -36,7 +37,9 @@ func (e *ChannelError) Code() string { return e.code } +// ChannelLog stores the HTTP traces and errors generated by an interaction with a channel. type ChannelLog struct { + uuid uuids.UUID type_ ChannelLogType channel Channel msgID MsgID @@ -47,16 +50,31 @@ type ChannelLog struct { elapsed time.Duration } -func NewChannelLogForIncoming(r *httpx.Recorder, channel Channel) *ChannelLog { - return &ChannelLog{type_: ChannelLogTypeUnknown, recorder: r, channel: channel, createdOn: dates.Now()} +// NewChannelLogForIncoming creates a new channel log for an incoming request, the type of which won't be known +// until the handler completes. +func NewChannelLogForIncoming(r *httpx.Recorder, ch Channel) *ChannelLog { + return newChannelLog(ChannelLogTypeUnknown, ch, r, NilMsgID) } +// NewChannelLogForSend creates a new channel log for a message send func NewChannelLogForSend(msg Msg) *ChannelLog { - return &ChannelLog{type_: ChannelLogTypeMsgSend, channel: msg.Channel(), msgID: msg.ID(), createdOn: dates.Now()} + return newChannelLog(ChannelLogTypeMsgSend, msg.Channel(), nil, msg.ID()) } -func NewChannelLog(t ChannelLogType, channel Channel) *ChannelLog { - return &ChannelLog{type_: t, channel: channel, createdOn: dates.Now()} +// NewChannelLog creates a new channel log with the given type and channel +func NewChannelLog(t ChannelLogType, ch Channel) *ChannelLog { + return newChannelLog(t, ch, nil, NilMsgID) +} + +func newChannelLog(t ChannelLogType, ch Channel, r *httpx.Recorder, mid MsgID) *ChannelLog { + return &ChannelLog{ + uuid: uuids.New(), + type_: t, + channel: ch, + recorder: r, + msgID: mid, + createdOn: dates.Now(), + } } // HTTP logs an outgoing HTTP request and response @@ -77,6 +95,10 @@ func (l *ChannelLog) End() { l.elapsed = time.Since(l.createdOn) } +func (l *ChannelLog) UUID() uuids.UUID { + return l.uuid +} + func (l *ChannelLog) Type() ChannelLogType { return l.type_ } diff --git a/channel_log_test.go b/channel_log_test.go index c7e4bf801..84e35ad9f 100644 --- a/channel_log_test.go +++ b/channel_log_test.go @@ -9,6 +9,7 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/httpx" + "github.com/nyaruka/gocommon/uuids" "github.com/stretchr/testify/assert" ) @@ -21,6 +22,9 @@ func TestChannelLog(t *testing.T) { })) defer httpx.SetRequestor(httpx.DefaultRequestor) + uuids.SetGenerator(uuids.NewSeededGenerator(1234)) + defer uuids.SetGenerator(uuids.DefaultGenerator) + channel := test.NewMockChannel("fef91e9b-a6ed-44fb-b6ce-feed8af585a8", "NX", "1234", "US", nil) clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel) @@ -40,10 +44,13 @@ func TestChannelLog(t *testing.T) { clog.Error(errors.New("this is an error")) clog.End() + assert.Equal(t, uuids.UUID("c00e5d67-c275-4389-aded-7d8b151cbd5b"), clog.UUID()) assert.Equal(t, courier.ChannelLogTypeTokenFetch, clog.Type()) assert.Equal(t, channel, clog.Channel()) + assert.Equal(t, courier.NilMsgID, clog.MsgID()) assert.Equal(t, 2, len(clog.HTTPLogs())) assert.Equal(t, 1, len(clog.Errors())) + assert.False(t, clog.CreatedOn().IsZero()) assert.Greater(t, clog.Elapsed(), time.Duration(0)) hlog1 := clog.HTTPLogs()[0] @@ -60,4 +67,10 @@ func TestChannelLog(t *testing.T) { err1 := clog.Errors()[0] assert.Equal(t, "this is an error", err1.Message()) assert.Equal(t, "", err1.Code()) + + clog.SetMsgID(courier.NewMsgID(123)) + clog.SetType(courier.ChannelLogTypeEventReceive) + + assert.Equal(t, courier.NewMsgID(123), clog.MsgID()) + assert.Equal(t, courier.ChannelLogTypeEventReceive, clog.Type()) } From 0665b56725e93bbce7b71858f00e016baa3b3541 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 25 Aug 2022 13:09:43 -0500 Subject: [PATCH 104/294] Fix insert channel log SQL --- backends/rapidpro/log.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backends/rapidpro/log.go b/backends/rapidpro/log.go index 01924a23d..72742a5fc 100644 --- a/backends/rapidpro/log.go +++ b/backends/rapidpro/log.go @@ -12,8 +12,7 @@ import ( const insertLogSQL = ` INSERT INTO channels_channellog( log_type, channel_id, msg_id, http_logs, errors, is_error, created_on, elapsed_ms) - VALUES(:log_type, :channel_id, :msg_id, :http_logs, :errors, :is_error, :created_on, :elapsed_ms) - RETURNING id` + VALUES(:log_type, :channel_id, :msg_id, :http_logs, :errors, :is_error, :created_on, :elapsed_ms)` // ChannelLog is our DB specific struct for logs type ChannelLog struct { From 7118e691a62ea8055490dafef39d4880d6aa9a70 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 25 Aug 2022 13:10:18 -0500 Subject: [PATCH 105/294] Update CHANGELOG.md for v7.5.18 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bd90038a..a5341df9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.18 +---------- + * Fix insert channel log SQL + v7.5.17 ---------- * Fix writing channel logs From 7ac746fe62b29fcc0332dd8eb9095e264cae3b59 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 25 Aug 2022 13:23:09 -0500 Subject: [PATCH 106/294] Don't fail CI for codecov problems --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 96328b1dc..0c468dd84 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: if: success() uses: codecov/codecov-action@v2 with: - fail_ci_if_error: true + fail_ci_if_error: false release: name: Release From abf1143a72f3bafc429c96642e4afcd3c1ad3c44 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 25 Aug 2022 14:53:44 -0500 Subject: [PATCH 107/294] Use generics with batch committer and add tests for committing channel logs --- backends/rapidpro/backend.go | 4 +-- backends/rapidpro/backend_test.go | 37 ++++++++++++++------ backends/rapidpro/{log.go => channel_log.go} | 4 +-- batch/batch.go | 13 +++---- 4 files changed, 38 insertions(+), 20 deletions(-) rename backends/rapidpro/{log.go => channel_log.go} (90%) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 7aa330df4..46a708018 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -384,9 +384,9 @@ func (b *backend) WriteChannelLog(ctx context.Context, clog *courier.ChannelLog) timeout, cancel := context.WithTimeout(ctx, backendTimeout) defer cancel() - err := writeChannelLog(timeout, b, clog) + err := queueChannelLog(timeout, b, clog) if err != nil { - logrus.WithError(err).Error("error writing channel log") + logrus.WithError(err).Error("error queuing channel log") } return nil diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index a4ccb3d05..4b25a170c 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -515,7 +515,8 @@ func (ts *BackendTestSuite) TestMsgStatus() { status.SetExternalID("ext0") err := ts.b.WriteMsgStatus(ctx, status) ts.NoError(err) - time.Sleep(time.Second) + + time.Sleep(time.Second) // give committer time to write this m := readMsgFromDB(ts.b, courier.NewMsgID(10001)) ts.Equal(courier.MsgWired, m.Status_) @@ -530,7 +531,8 @@ func (ts *BackendTestSuite) TestMsgStatus() { status = ts.b.NewMsgStatusForID(channel, courier.NewMsgID(10001), courier.MsgSent) err = ts.b.WriteMsgStatus(ctx, status) ts.NoError(err) - time.Sleep(time.Second) + + time.Sleep(time.Second) // give committer time to write this m = readMsgFromDB(ts.b, courier.NewMsgID(10001)) ts.Equal(courier.MsgSent, m.Status_) @@ -553,7 +555,8 @@ func (ts *BackendTestSuite) TestMsgStatus() { status = ts.b.NewMsgStatusForID(channel, courier.NewMsgID(10002), courier.MsgSent) err = ts.b.WriteMsgStatus(ctx, status) ts.NoError(err) - time.Sleep(time.Second) + + time.Sleep(time.Second) // give committer time to write this m = readMsgFromDB(ts.b, courier.NewMsgID(10002)) ts.Equal(courier.MsgPending, m.Status_) @@ -577,7 +580,8 @@ func (ts *BackendTestSuite) TestMsgStatus() { status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgWired) err = ts.b.WriteMsgStatus(ctx, status) ts.NoError(err) - time.Sleep(time.Second) + + time.Sleep(time.Second) // give committer time to write this m = readMsgFromDB(ts.b, courier.NewMsgID(10000)) ts.Equal(courier.MsgWired, m.Status_) @@ -619,7 +623,8 @@ func (ts *BackendTestSuite) TestMsgStatus() { status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgErrored) err = ts.b.WriteMsgStatus(ctx, status) ts.NoError(err) - time.Sleep(time.Second) + + time.Sleep(time.Second) // give committer time to write this m = readMsgFromDB(ts.b, courier.NewMsgID(10000)) ts.Equal(m.Status_, courier.MsgErrored) @@ -632,7 +637,8 @@ func (ts *BackendTestSuite) TestMsgStatus() { status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgErrored) err = ts.b.WriteMsgStatus(ctx, status) ts.NoError(err) - time.Sleep(time.Second) + + time.Sleep(time.Second) // give committer time to write this m = readMsgFromDB(ts.b, courier.NewMsgID(10000)) ts.Equal(m.Status_, courier.MsgErrored) @@ -642,7 +648,8 @@ func (ts *BackendTestSuite) TestMsgStatus() { // third go status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgErrored) err = ts.b.WriteMsgStatus(ctx, status) - time.Sleep(time.Second) + + time.Sleep(time.Second) // give committer time to write this ts.NoError(err) m = readMsgFromDB(ts.b, courier.NewMsgID(10000)) @@ -945,9 +952,13 @@ func (ts *BackendTestSuite) TestChannel() { } -func (ts *BackendTestSuite) TestChanneLog() { - channel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") +func (ts *BackendTestSuite) TestWriteChanneLog() { ctx := context.Background() + channel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") + + defer func() { + ts.b.db.MustExecContext(ctx, "DELETE FROM channels_channellog") + }() httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ "https://api.messages.com/send.json": { @@ -964,8 +975,14 @@ func (ts *BackendTestSuite) TestChanneLog() { clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel) clog.HTTP(trace) - err = writeChannelLog(ctx, ts.b, clog) + err = ts.b.WriteChannelLog(ctx, clog) ts.NoError(err) + + time.Sleep(time.Second) // give committer time to write this + + assertdb.Query(ts.T(), ts.b.db, `SELECT count(*) FROM channels_channellog`).Returns(1) + assertdb.Query(ts.T(), ts.b.db, `SELECT channel_id, http_logs->0->>'url' AS url FROM channels_channellog`). + Columns(map[string]interface{}{"channel_id": int64(channel.ID()), "url": "https://api.messages.com/send.json"}) } func (ts *BackendTestSuite) TestWriteAttachment() { diff --git a/backends/rapidpro/log.go b/backends/rapidpro/channel_log.go similarity index 90% rename from backends/rapidpro/log.go rename to backends/rapidpro/channel_log.go index 72742a5fc..b6808de69 100644 --- a/backends/rapidpro/log.go +++ b/backends/rapidpro/channel_log.go @@ -36,8 +36,8 @@ type channelError struct { Code string `json:"code"` } -// WriteChannelLog writes the passed in channel log to the database, we do not queue on errors but instead just throw away the log -func writeChannelLog(ctx context.Context, b *backend, clog *courier.ChannelLog) error { +// queues the passed in channel log the committer, we do not queue on errors but instead just throw away the log +func queueChannelLog(ctx context.Context, b *backend, clog *courier.ChannelLog) error { dbChan := clog.Channel().(*DBChannel) isError := len(clog.Errors()) > 0 diff --git a/batch/batch.go b/batch/batch.go index 1848ce911..78b55fff6 100644 --- a/batch/batch.go +++ b/batch/batch.go @@ -47,8 +47,9 @@ func NewCommitter(label string, db *sqlx.DB, sql string, timeout time.Duration, // Start starts our committer func (c *committer) Start() { + c.wg.Add(1) + go func() { - c.wg.Add(1) defer c.wg.Done() for { @@ -117,7 +118,7 @@ func (c *committer) flush(size int) bool { for len(values) > 0 { ids := make(map[string]bool, len(values)) dupes := make([]Value, 0) - batch := make([]interface{}, 0, len(values)) + batch := make([]Value, 0, len(values)) // dedupe our values into a batch, we don't want to do a batch update that includes the same row more // thank once. we dedupe our batch here and commit in another query @@ -144,10 +145,10 @@ func (c *committer) flush(size int) bool { // if we received an error, try again one at a time (in case it is one value hanging us up) if err != nil { for _, v := range batch { - err = batchSQL(ctx, c.label, c.db, c.sql, []interface{}{v}) + err = batchSQL(ctx, c.label, c.db, c.sql, []Value{v}) if err != nil { if c.callback != nil { - c.callback(errors.Wrapf(err, "%s: error committing value", c.label), v.(Value)) + c.callback(errors.Wrapf(err, "%s: error committing value", c.label), v) } } } @@ -172,7 +173,7 @@ type committer struct { buffer chan Value } -func batchSQL(ctx context.Context, label string, db *sqlx.DB, sql string, vs []interface{}) error { +func batchSQL[T any](ctx context.Context, label string, db *sqlx.DB, sql string, vs []T) error { // no values, nothing to do if len(vs) == 0 { return nil @@ -185,7 +186,7 @@ func batchSQL(ctx context.Context, label string, db *sqlx.DB, sql string, vs []i return err } - logrus.WithField("elapsed", time.Since(start)).WithField("rows", len(vs)).Infof("%s bulk sql complete", label) + logrus.WithField("elapsed", time.Since(start)).WithField("rows", len(vs)).Debugf("%s bulk sql complete", label) return nil } From 724b5c811a2bc71628feacbdb4921b01f585150b Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 25 Aug 2022 15:20:03 -0500 Subject: [PATCH 108/294] Tidying of some tests --- handlers/arabiacell/arabiacell_test.go | 24 +++-- handlers/blackmyna/blackmyna_test.go | 64 +++++++++---- handlers/burstsms/burstsms_test.go | 45 +++++---- handlers/chikka/chikka_test.go | 81 ++++++++++++---- handlers/clickatell/clickatell_test.go | 122 ++++++++++++++++++------- 5 files changed, 242 insertions(+), 94 deletions(-) diff --git a/handlers/arabiacell/arabiacell_test.go b/handlers/arabiacell/arabiacell_test.go index 001aba3b2..5276fb3a7 100644 --- a/handlers/arabiacell/arabiacell_test.go +++ b/handlers/arabiacell/arabiacell_test.go @@ -13,17 +13,27 @@ var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "AC", "2020", "US", nil), } -var ( +const ( receiveURL = "/c/ac/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" - - validReceive = "B=Msg&M=254791541111" - missingNumber = "B=Msg" ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111")}, - {Label: "Receive Missing Number", URL: receiveURL, Data: missingNumber, ExpectedStatus: 400, ExpectedResponse: "required field 'M'"}, + { + Label: "Receive Valid", + URL: receiveURL, + Data: "B=Msg&M=254791541111", + ExpectedStatus: 200, + ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: Sp("tel:+254791541111"), + }, + { + Label: "Receive Missing Number", + URL: receiveURL, + Data: "B=Msg", + ExpectedStatus: 400, + ExpectedResponse: "required field 'M'", + }, } func TestHandler(t *testing.T) { diff --git a/handlers/blackmyna/blackmyna_test.go b/handlers/blackmyna/blackmyna_test.go index 7f9d199ce..61f6e1dcc 100644 --- a/handlers/blackmyna/blackmyna_test.go +++ b/handlers/blackmyna/blackmyna_test.go @@ -13,30 +13,56 @@ var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "BM", "2020", "US", nil), } -var ( +const ( receiveURL = "/c/bm/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" statusURL = "/c/bm/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/" - - emptyReceive = receiveURL + "" - validReceive = receiveURL + "?to=3344&smsc=ncell&from=%2B9779814641111&text=Msg" - invalidURN = receiveURL + "?to=3344&smsc=ncell&from=MTN&text=Msg" - missingText = receiveURL + "?to=3344&smsc=ncell&from=%2B9779814641111" - - missingStatus = statusURL + "?" - invalidStatus = statusURL + "?id=bmID&status=13" - validStatus = statusURL + "?id=bmID&status=2" ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+9779814641111")}, - {Label: "Invalid URN", URL: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Receive Empty", URL: emptyReceive, ExpectedStatus: 400, ExpectedResponse: "field 'text' required"}, - {Label: "Receive Missing Text", URL: missingText, ExpectedStatus: 400, ExpectedResponse: "field 'text' required"}, - - {Label: "Status Invalid", URL: invalidStatus, ExpectedStatus: 400, ExpectedResponse: "unknown status"}, - {Label: "Status Missing", URL: missingStatus, ExpectedStatus: 400, ExpectedResponse: "field 'status' required"}, - {Label: "Valid Status", URL: validStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`}, + { + Label: "Receive Valid", + URL: receiveURL + "?to=3344&smsc=ncell&from=%2B9779814641111&text=Msg", + ExpectedStatus: 200, + ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: Sp("tel:+9779814641111"), + }, + { + Label: "Invalid URN", + URL: receiveURL + "?to=3344&smsc=ncell&from=MTN&text=Msg", + ExpectedStatus: 400, + ExpectedResponse: "phone number supplied is not a number", + }, + { + Label: "Receive Empty", + URL: receiveURL + "", + ExpectedStatus: 400, + ExpectedResponse: "field 'text' required", + }, + { + Label: "Receive Missing Text", + URL: receiveURL + "?to=3344&smsc=ncell&from=%2B9779814641111", + ExpectedStatus: 400, + ExpectedResponse: "field 'text' required", + }, + { + Label: "Status Invalid", + URL: statusURL + "?id=bmID&status=13", + ExpectedStatus: 400, + ExpectedResponse: "unknown status", + }, + { + Label: "Status Missing", + URL: statusURL + "?", + ExpectedStatus: 400, + ExpectedResponse: "field 'status' required", + }, + { + Label: "Valid Status", + URL: statusURL + "?id=bmID&status=2", + ExpectedStatus: 200, + ExpectedResponse: `"status":"F"`, + }, } func TestHandler(t *testing.T) { diff --git a/handlers/burstsms/burstsms_test.go b/handlers/burstsms/burstsms_test.go index 4144a788b..2f64e519d 100644 --- a/handlers/burstsms/burstsms_test.go +++ b/handlers/burstsms/burstsms_test.go @@ -13,26 +13,39 @@ var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "BS", "2020", "US", nil), } -var ( +const ( receiveURL = "/c/bs/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" - - validReceive = "response=Msg&mobile=254791541111" - missingNumber = "response=Msg" - - statusURL = "/c/bs/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/" - - validStatus = "message_id=12345&status=pending" - invalidStatus = "message_id=12345&status=unknown" + statusURL = "/c/bs/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/" ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL + "?" + validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111")}, - {Label: "Receive Missing Number", URL: receiveURL + "?" + missingNumber, ExpectedStatus: 400, ExpectedResponse: "required field 'mobile'"}, - - {Label: "Status Valid", URL: statusURL + "?" + validStatus, ExpectedStatus: 200, ExpectedResponse: "Status Update Accepted", - ExpectedExternalID: Sp("12345"), ExpectedMsgStatus: Sp("S")}, - {Label: "Receive Invalid Status", URL: statusURL + "?" + invalidStatus, ExpectedStatus: 400, ExpectedResponse: "unknown status value"}, + { + Label: "Receive Valid", + URL: receiveURL + "?response=Msg&mobile=254791541111", + ExpectedStatus: 200, + ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: Sp("tel:+254791541111"), + }, + { + Label: "Receive Missing Number", + URL: receiveURL + "?response=Msg", + ExpectedStatus: 400, + ExpectedResponse: "required field 'mobile'", + }, + { + Label: "Status Valid", + URL: statusURL + "?message_id=12345&status=pending", + ExpectedStatus: 200, + ExpectedResponse: "Status Update Accepted", + ExpectedExternalID: Sp("12345"), + ExpectedMsgStatus: Sp("S")}, + { + Label: "Receive Invalid Status", + URL: statusURL + "?message_id=12345&status=unknown", + ExpectedStatus: 400, + ExpectedResponse: "unknown status value", + }, } func TestHandler(t *testing.T) { diff --git a/handlers/chikka/chikka_test.go b/handlers/chikka/chikka_test.go index f07a7753c..87e8bd95c 100644 --- a/handlers/chikka/chikka_test.go +++ b/handlers/chikka/chikka_test.go @@ -14,30 +14,71 @@ var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "CK", "2020", "US", nil), } -var ( - receiveURL = "/c/ck/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive" - validReceive = "message_type=incoming&mobile_number=639178020779&request_id=4004&message=Hello+World×tamp=1457670059.69" - invalidURN = "message_type=incoming&mobile_number=MTN&request_id=4004&message=Hello+World×tamp=1457670059.69" - missingParamsReceive = "message_type=incoming&message=Hello+World×tamp=1457670059.69" - - validSentStatus = "message_type=outgoing&message_id=10&status=SENT" - validFailedStatus = "message_type=outgoing&message_id=10&status=FAILED" - invalidStatus = "message_type=outgoing&message_id=10&status=UNKNOWN" - missingStatusParams = "message_type=outgoing" +const ( + receiveURL = "/c/ck/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive" ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("tel:+639178020779"), ExpectedExternalID: Sp("4004"), - ExpectedDate: time.Date(2016, 03, 11, 04, 20, 59, 690000128, time.UTC), + { + Label: "Receive Valid", + URL: receiveURL, + Data: "message_type=incoming&mobile_number=639178020779&request_id=4004&message=Hello+World×tamp=1457670059.69", + ExpectedStatus: 200, + ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: Sp("tel:+639178020779"), + ExpectedExternalID: Sp("4004"), + ExpectedDate: time.Date(2016, 03, 11, 04, 20, 59, 690000128, time.UTC), + }, + { + Label: "Invalid URN", + URL: receiveURL, + Data: "message_type=incoming&mobile_number=MTN&request_id=4004&message=Hello+World×tamp=1457670059.69", + ExpectedStatus: 400, + ExpectedResponse: "phone number supplied is not a number", + }, + { + Label: "Receive Mising Params", + URL: receiveURL, + Data: "message_type=incoming&message=Hello+World×tamp=1457670059.69", + ExpectedStatus: 400, + ExpectedResponse: "Field validation for 'RequestID' failed", + }, + { + Label: "Ignore Invalid message_type", + URL: receiveURL, + Data: "message_type=invalid", + ExpectedStatus: 200, + ExpectedResponse: "unknown message_type request", + }, + { + Label: "Status Sent Valid", + URL: receiveURL, + Data: "message_type=outgoing&message_id=10&status=SENT", + ExpectedStatus: 200, + ExpectedResponse: `"status":"S"`, + }, + { + Label: "Status Failed Valid", + URL: receiveURL, + Data: "message_type=outgoing&message_id=10&status=FAILED", + ExpectedStatus: 200, + ExpectedResponse: `"status":"F"`, + }, + { + Label: "Status Invalid", + URL: receiveURL, + Data: "message_type=outgoing&message_id=10&status=UNKNOWN", + ExpectedStatus: 400, + ExpectedResponse: `must be either 'SENT' or 'FAILED'`, + }, + { + Label: "Status Missing Params", + URL: receiveURL, + Data: "message_type=outgoing", + ExpectedStatus: 400, + ExpectedResponse: `Field validation for 'Status' failed `, }, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Receive Mising Params", URL: receiveURL, Data: missingParamsReceive, ExpectedStatus: 400, ExpectedResponse: "Field validation for 'RequestID' failed"}, - {Label: "Ignore Invalid message_type", URL: receiveURL, Data: "message_type=invalid", ExpectedStatus: 200, ExpectedResponse: "unknown message_type request"}, - {Label: "Status Sent Valid", URL: receiveURL, Data: validSentStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, - {Label: "Status Failed Valid", URL: receiveURL, Data: validFailedStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`}, - {Label: "Status Invalid", URL: receiveURL, Data: invalidStatus, ExpectedStatus: 400, ExpectedResponse: `must be either 'SENT' or 'FAILED'`}, - {Label: "Status Missing Params", URL: receiveURL, Data: missingStatusParams, ExpectedStatus: 400, ExpectedResponse: `Field validation for 'Status' failed `}, } func TestHandler(t *testing.T) { diff --git a/handlers/clickatell/clickatell_test.go b/handlers/clickatell/clickatell_test.go index 2489e44d7..e9f55ede6 100644 --- a/handlers/clickatell/clickatell_test.go +++ b/handlers/clickatell/clickatell_test.go @@ -93,7 +93,7 @@ var testChannels = []courier.Channel{ }), } -var ( +const ( statusURL = "/c/ct/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status" receiveURL = "/c/ct/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive" @@ -128,40 +128,98 @@ var ( "text": "%00m%00e%00x%00i%00c%00o%00+%00k%00+%00m%00i%00s%00+%00p%00a%00p%00a%00s%00+%00n%00o%00+%00t%00e%00n%00%ED%00a%00+%00d%00i%00n%00e%00r%00o%00+%00p%00a%00r%00a%00+%00c%00o%00m%00p%00r%00a%00r%00n%00o%00s%00+%00l%00o%00+%00q%00+%00q%00u%00e%00r%00%ED%00a%00m%00o%00s%00.%00.", "charset": "UTF-16BE" }` - - statusFailed = `{ - "messageId": "msg1", - "statusCode": 5 - }` - statusSent = `{ - "messageId": "msg1", - "statusCode": 4 - }` - - statusUnexpected = `{ - "messageId": "msg1", - "statusCode": -1 - }` ) var testCases = []ChannelHandleTestCase{ - {Label: "Valid Receive", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Hello World!"), ExpectedURN: Sp("tel:+250788383383"), ExpectedExternalID: Sp("1234"), ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC)}, - {Label: "Valid Receive ISO-8859-1", URL: receiveURL, Data: receiveValidMessageISO8859_1, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(`hello!`), ExpectedURN: Sp("tel:+250788383383"), ExpectedExternalID: Sp("1234"), ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC)}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Error invalid JSON", URL: receiveURL, Data: "foo", ExpectedStatus: 400, ExpectedResponse: `unable to parse request JSON`}, - {Label: "Error missing JSON", URL: receiveURL, Data: "{}", ExpectedStatus: 400, ExpectedResponse: `missing one of 'messageId`}, - {Label: "Valid Receive UTF-16BE", URL: receiveURL, Data: receiveValidMessageUTF16BE, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("mexico k mis papas no tenýa dinero para comprarnos lo q querýamos.."), ExpectedURN: Sp("tel:+250788383383"), - ExpectedExternalID: Sp("1234"), ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC), - }, - {Label: "Valid Failed status report", URL: statusURL, Data: statusFailed, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`}, - {Label: "Valid Delivered status report", URL: statusURL, Data: statusSent, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, - {Label: "Unexpected status report", URL: statusURL, Data: statusUnexpected, ExpectedStatus: 400, ExpectedResponse: `unknown status '-1', must be one`}, - - {Label: "Invalid status report", URL: statusURL, Data: "{}", ExpectedStatus: 400, ExpectedResponse: `missing one of 'messageId'`}, - {Label: "Invalid JSON", URL: statusURL, Data: "foo", ExpectedStatus: 400, ExpectedResponse: `unable to parse request JSON`}, + { + Label: "Valid Receive", + URL: receiveURL, + Data: receiveValidMessage, + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Hello World!"), + ExpectedURN: Sp("tel:+250788383383"), + ExpectedExternalID: Sp("1234"), + ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC), + }, + { + Label: "Valid Receive ISO-8859-1", + URL: receiveURL, + Data: receiveValidMessageISO8859_1, + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(`hello!`), + ExpectedURN: Sp("tel:+250788383383"), + ExpectedExternalID: Sp("1234"), + ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC), + }, + { + Label: "Invalid URN", + URL: receiveURL, + Data: invalidURN, + ExpectedStatus: 400, + ExpectedResponse: "phone number supplied is not a number", + }, + { + Label: "Error invalid JSON", + URL: receiveURL, + Data: "foo", + ExpectedStatus: 400, + ExpectedResponse: `unable to parse request JSON`, + }, + { + Label: "Error missing JSON", + URL: receiveURL, + Data: "{}", + ExpectedStatus: 400, + ExpectedResponse: `missing one of 'messageId`, + }, + { + Label: "Valid Receive UTF-16BE", + URL: receiveURL, + Data: receiveValidMessageUTF16BE, + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("mexico k mis papas no tenýa dinero para comprarnos lo q querýamos.."), + ExpectedURN: Sp("tel:+250788383383"), + ExpectedExternalID: Sp("1234"), + ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC), + }, + { + Label: "Valid Failed status report", + URL: statusURL, + Data: `{"messageId": "msg1", "statusCode": 5}`, + ExpectedStatus: 200, + ExpectedResponse: `"status":"F"`, + }, + { + Label: "Valid Delivered status report", + URL: statusURL, + Data: `{"messageId": "msg1", "statusCode": 4}`, + ExpectedStatus: 200, + ExpectedResponse: `"status":"S"`, + }, + { + Label: "Unexpected status report", + URL: statusURL, + Data: `{"messageId": "msg1", "statusCode": -1}`, + ExpectedStatus: 400, + ExpectedResponse: `unknown status '-1', must be one`, + }, + { + Label: "Invalid status report", + URL: statusURL, + Data: "{}", + ExpectedStatus: 400, + ExpectedResponse: `missing one of 'messageId'`, + }, + { + Label: "Invalid JSON", + URL: statusURL, + Data: "foo", + ExpectedStatus: 400, + ExpectedResponse: `unable to parse request JSON`, + }, } func TestHandler(t *testing.T) { From 068b15b47ccba2d26cabb3cb7c23f994bb1c9161 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 25 Aug 2022 18:30:57 -0500 Subject: [PATCH 109/294] Include requests made by DescribeURN methods in the channel log for a receive --- backend.go | 6 +- backends/rapidpro/backend.go | 12 ++-- backends/rapidpro/backend_test.go | 87 +++++++++++++---------- backends/rapidpro/channel_event.go | 13 ++-- backends/rapidpro/contact.go | 9 +-- backends/rapidpro/msg.go | 19 ++--- handler_test.go | 2 +- handlers/africastalking/africastalking.go | 2 +- handlers/blackmyna/blackmyna.go | 2 +- handlers/bongolive/bongolive.go | 2 +- handlers/chikka/chikka.go | 2 +- handlers/clickatell/clickatell.go | 2 +- handlers/clickmobile/clickmobile.go | 2 +- handlers/dart/dart.go | 2 +- handlers/discord/discord.go | 2 +- handlers/dmark/dmark.go | 2 +- handlers/external/external.go | 4 +- handlers/facebook/facebook.go | 10 +-- handlers/facebookapp/facebookapp.go | 16 ++--- handlers/firebase/firebase.go | 4 +- handlers/freshchat/freshchat.go | 2 +- handlers/generic.go | 2 +- handlers/globe/globe.go | 2 +- handlers/highconnection/highconnection.go | 2 +- handlers/hormuud/hormuud.go | 2 +- handlers/i2sms/i2sms.go | 2 +- handlers/infobip/infobip.go | 2 +- handlers/jasmin/jasmin.go | 2 +- handlers/jiochat/jiochat.go | 4 +- handlers/junebug/junebug.go | 2 +- handlers/kaleyra/kaleyra.go | 2 +- handlers/kannel/kannel.go | 2 +- handlers/line/line.go | 2 +- handlers/m3tech/m3tech.go | 2 +- handlers/macrokiosk/macrokiosk.go | 2 +- handlers/mblox/mblox.go | 2 +- handlers/mtarget/mtarget.go | 4 +- handlers/nexmo/nexmo.go | 2 +- handlers/novo/novo.go | 2 +- handlers/playmobile/playmobile.go | 2 +- handlers/plivo/plivo.go | 2 +- handlers/responses.go | 4 +- handlers/rocketchat/rocketchat.go | 2 +- handlers/shaqodoon/shaqodoon.go | 2 +- handlers/slack/slack.go | 2 +- handlers/smscentral/smscentral.go | 2 +- handlers/start/start.go | 2 +- handlers/telegram/telegram.go | 14 ++-- handlers/telesom/telesom.go | 2 +- handlers/test.go | 2 +- handlers/thinq/thinq.go | 2 +- handlers/twiml/twiml.go | 6 +- handlers/twitter/twitter.go | 2 +- handlers/viber/viber.go | 8 +-- handlers/vk/vk.go | 6 +- handlers/wavy/wavy.go | 2 +- handlers/wechat/wechat.go | 4 +- handlers/whatsapp/whatsapp.go | 2 +- handlers/yo/yo.go | 4 +- handlers/zenvia/zenvia.go | 2 +- handlers/zenviaold/zenviaold.go | 2 +- test/backend.go | 6 +- 62 files changed, 169 insertions(+), 155 deletions(-) diff --git a/backend.go b/backend.go index 7679fde04..5e33e255d 100644 --- a/backend.go +++ b/backend.go @@ -30,7 +30,7 @@ type Backend interface { GetChannelByAddress(context.Context, ChannelType, ChannelAddress) (Channel, error) // GetContact returns (or creates) the contact for the passed in channel and URN - GetContact(context context.Context, channel Channel, urn urns.URN, auth string, name string) (Contact, error) + GetContact(context.Context, Channel, urns.URN, string, string, *ChannelLog) (Contact, error) // AddURNtoContact adds a URN to the passed in contact AddURNtoContact(context context.Context, channel Channel, contact Contact, urn urns.URN) (urns.URN, error) @@ -45,7 +45,7 @@ type Backend interface { NewIncomingMsg(channel Channel, urn urns.URN, text string) Msg // WriteMsg writes the passed in message to our backend - WriteMsg(context.Context, Msg) error + WriteMsg(context.Context, Msg, *ChannelLog) error // NewMsgStatusForID creates a new Status object for the given message id NewMsgStatusForID(Channel, MsgID, MsgStatusValue) MsgStatus @@ -60,7 +60,7 @@ type Backend interface { NewChannelEvent(Channel, ChannelEventType, urns.URN) ChannelEvent // WriteChannelEvent writes the passed in channel even returning any error - WriteChannelEvent(context.Context, ChannelEvent) error + WriteChannelEvent(context.Context, ChannelEvent, *ChannelLog) error // WriteChannelLog writes the passed in channel log to our backend WriteChannelLog(context.Context, *ChannelLog) error diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 46a708018..46dea60e3 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -63,9 +63,9 @@ func (b *backend) GetChannelByAddress(ctx context.Context, ct courier.ChannelTyp } // GetContact returns the contact for the passed in channel and URN -func (b *backend) GetContact(ctx context.Context, c courier.Channel, urn urns.URN, auth string, name string) (courier.Contact, error) { +func (b *backend) GetContact(ctx context.Context, c courier.Channel, urn urns.URN, auth string, name string, clog *courier.ChannelLog) (courier.Contact, error) { dbChannel := c.(*DBChannel) - return contactForURN(ctx, b, dbChannel.OrgID_, dbChannel, urn, auth, name) + return contactForURN(ctx, b, dbChannel.OrgID_, dbChannel, urn, auth, name, clog) } // AddURNtoContact adds a URN to the passed in contact @@ -258,11 +258,11 @@ func (b *backend) MarkOutgoingMsgComplete(ctx context.Context, msg courier.Msg, } // WriteMsg writes the passed in message to our store -func (b *backend) WriteMsg(ctx context.Context, m courier.Msg) error { +func (b *backend) WriteMsg(ctx context.Context, m courier.Msg, clog *courier.ChannelLog) error { timeout, cancel := context.WithTimeout(ctx, backendTimeout) defer cancel() - return writeMsg(timeout, b, m) + return writeMsg(timeout, b, m, clog) } // NewStatusUpdateForID creates a new Status object for the given message id @@ -372,11 +372,11 @@ func (b *backend) NewChannelEvent(channel courier.Channel, eventType courier.Cha } // WriteChannelEvent writes the passed in channel even returning any error -func (b *backend) WriteChannelEvent(ctx context.Context, event courier.ChannelEvent) error { +func (b *backend) WriteChannelEvent(ctx context.Context, event courier.ChannelEvent, clog *courier.ChannelLog) error { timeout, cancel := context.WithTimeout(ctx, backendTimeout) defer cancel() - return writeChannelEvent(timeout, b, event) + return writeChannelEvent(timeout, b, event, clog) } // WriteChannelLog persists the passed in log to our database, for rapidpro we swallow all errors, logging isn't critical diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 4b25a170c..ebee01da9 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -246,19 +246,20 @@ func (ts *BackendTestSuite) TestDeleteMsgWithExternalID() { func (ts *BackendTestSuite) TestContact() { knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) urn, _ := urns.NewTelURNForCountry("12065551518", "US") ctx := context.Background() now := time.Now() // create our new contact - contact, err := contactForURN(ctx, ts.b, knChannel.OrgID(), knChannel, urn, "", "Ryan Lewis") + contact, err := contactForURN(ctx, ts.b, knChannel.OrgID(), knChannel, urn, "", "Ryan Lewis", clog) ts.NoError(err) now2 := time.Now() // load this contact again by URN, should be same contact, name unchanged - contact2, err := contactForURN(ctx, ts.b, knChannel.OrgID(), knChannel, urn, "", "Other Name") + contact2, err := contactForURN(ctx, ts.b, knChannel.OrgID(), knChannel, urn, "", "Other Name", clog) ts.NoError(err) ts.Equal(contact.UUID_, contact2.UUID_) @@ -272,7 +273,7 @@ func (ts *BackendTestSuite) TestContact() { // load a contact by URN instead (this one is in our testdata) cURN, _ := urns.NewTelURNForCountry("+12067799192", "US") - contact, err = contactForURN(ctx, ts.b, knChannel.OrgID(), knChannel, cURN, "", "") + contact, err = contactForURN(ctx, ts.b, knChannel.OrgID(), knChannel, cURN, "", "", clog) ts.NoError(err) ts.NotNil(contact) @@ -284,7 +285,7 @@ func (ts *BackendTestSuite) TestContact() { // long name are truncated longName := "LongRandomNameHPGBRDjZvkz7y58jI2UPkio56IKGaMvaeDTvF74Q5SUkIHozFn1MLELfjX7vRrFto8YG2KPVaWzekgmFbkuxujIotFAgfhHqoHKW5c177FUtKf5YK9KbY8hp0x7PxIFY3MS5lMyMA5ELlqIgikThpr" - contact3, err := contactForURN(ctx, ts.b, knChannel.OrgID(), knChannel, urn, "", longName) + contact3, err := contactForURN(ctx, ts.b, knChannel.OrgID(), knChannel, urn, "", longName, clog) ts.NoError(err) ts.Equal(null.String(longName[0:127]), contact3.Name_) @@ -293,6 +294,7 @@ func (ts *BackendTestSuite) TestContact() { func (ts *BackendTestSuite) TestContactRace() { knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) urn, _ := urns.NewTelURNForCountry("12065551518", "US") urnSleep = true @@ -305,10 +307,10 @@ func (ts *BackendTestSuite) TestContactRace() { var err1, err2 error go func() { - contact1, err1 = contactForURN(ctx, ts.b, knChannel.OrgID(), knChannel, urn, "", "Ryan Lewis") + contact1, err1 = contactForURN(ctx, ts.b, knChannel.OrgID(), knChannel, urn, "", "Ryan Lewis", clog) }() go func() { - contact2, err2 = contactForURN(ctx, ts.b, knChannel.OrgID(), knChannel, urn, "", "Ryan Lewis") + contact2, err2 = contactForURN(ctx, ts.b, knChannel.OrgID(), knChannel, urn, "", "Ryan Lewis", clog) }() time.Sleep(time.Second) @@ -320,12 +322,13 @@ func (ts *BackendTestSuite) TestContactRace() { func (ts *BackendTestSuite) TestAddAndRemoveContactURN() { knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) ctx := context.Background() cURN, err := urns.NewTelURNForCountry("+12067799192", "US") ts.NoError(err) - contact, err := contactForURN(ctx, ts.b, knChannel.OrgID_, knChannel, cURN, "", "") + contact, err := contactForURN(ctx, ts.b, knChannel.OrgID_, knChannel, cURN, "", "", clog) ts.NoError(err) ts.NotNil(contact) @@ -362,17 +365,18 @@ func (ts *BackendTestSuite) TestAddAndRemoveContactURN() { func (ts *BackendTestSuite) TestContactURN() { knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") twChannel := ts.getChannel("TW", "dbc126ed-66bc-4e28-b67b-81dc3327c96a") + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) urn, _ := urns.NewTelURNForCountry("12065551515", "US") ctx := context.Background() - contact, err := contactForURN(ctx, ts.b, knChannel.OrgID_, knChannel, urn, "", "") + contact, err := contactForURN(ctx, ts.b, knChannel.OrgID_, knChannel, urn, "", "", clog) ts.NoError(err) tx, err := ts.b.db.Beginx() ts.NoError(err) - contact, err = contactForURN(ctx, ts.b, twChannel.OrgID_, twChannel, urn, "chestnut", "") + contact, err = contactForURN(ctx, ts.b, twChannel.OrgID_, twChannel, urn, "chestnut", "", clog) ts.NoError(err) contactURNs, err := contactURNsForContact(tx, contact.ID_) @@ -419,11 +423,11 @@ func (ts *BackendTestSuite) TestContactURN() { tgChannel := ts.getChannel("TG", "dbc126ed-66bc-4e28-b67b-81dc3327c98a") tgURN, _ := urns.NewTelegramURN(12345, "") - tgContact, err := contactForURN(ctx, ts.b, tgChannel.OrgID_, tgChannel, tgURN, "", "") + tgContact, err := contactForURN(ctx, ts.b, tgChannel.OrgID_, tgChannel, tgURN, "", "", clog) ts.NoError(err) tgURNDisplay, _ := urns.NewTelegramURN(12345, "Jane") - displayContact, err := contactForURN(ctx, ts.b, tgChannel.OrgID_, tgChannel, tgURNDisplay, "", "") + displayContact, err := contactForURN(ctx, ts.b, tgChannel.OrgID_, tgChannel, tgURNDisplay, "", "", clog) ts.Equal(tgContact.URNID_, displayContact.URNID_) ts.Equal(tgContact.ID_, displayContact.ID_) @@ -444,13 +448,13 @@ func (ts *BackendTestSuite) TestContactURN() { wait.Add(2) go func() { var err2 error - contact2, err2 = contactForURN(ctx, ts.b, knChannel.OrgID(), knChannel, urn2, "", "") + contact2, err2 = contactForURN(ctx, ts.b, knChannel.OrgID(), knChannel, urn2, "", "", clog) ts.NoError(err2) wait.Done() }() go func() { var err3 error - contact3, err3 = contactForURN(ctx, ts.b, knChannel.OrgID(), knChannel, urn2, "", "") + contact3, err3 = contactForURN(ctx, ts.b, knChannel.OrgID(), knChannel, urn2, "", "", clog) ts.NoError(err3) wait.Done() }() @@ -466,10 +470,11 @@ func (ts *BackendTestSuite) TestContactURNPriority() { twChannel := ts.getChannel("TW", "dbc126ed-66bc-4e28-b67b-81dc3327c96a") knURN, _ := urns.NewTelURNForCountry("12065551111", "US") twURN, _ := urns.NewTelURNForCountry("12065552222", "US") + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) ctx := context.Background() - knContact, err := contactForURN(ctx, ts.b, knChannel.OrgID_, knChannel, knURN, "", "") + knContact, err := contactForURN(ctx, ts.b, knChannel.OrgID_, knChannel, knURN, "", "", clog) ts.NoError(err) tx, err := ts.b.db.Beginx() @@ -481,7 +486,7 @@ func (ts *BackendTestSuite) TestContactURNPriority() { // ok, now looking up our contact should reset our URNs and their affinity.. // TwitterURN should be first all all URNs should now use Twitter channel - twContact, err := contactForURN(ctx, ts.b, twChannel.OrgID_, twChannel, twURN, "", "") + twContact, err := contactForURN(ctx, ts.b, twChannel.OrgID_, twChannel, twURN, "", "", clog) ts.NoError(err) ts.Equal(twContact.ID_, knContact.ID_) @@ -504,6 +509,7 @@ func (ts *BackendTestSuite) TestContactURNPriority() { func (ts *BackendTestSuite) TestMsgStatus() { ctx := context.Background() channel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) now := time.Now().In(time.UTC) time.Sleep(2 * time.Millisecond) @@ -681,7 +687,7 @@ func (ts *BackendTestSuite) TestMsgStatus() { oldURN, _ = urns.NewWhatsAppURN("55999887766") newURN, _ = urns.NewWhatsAppURN("5599887766") tx, _ = ts.b.db.BeginTxx(ctx, nil) - contact, _ := contactForURN(ctx, ts.b, channel.OrgID_, channel, oldURN, "", "") + contact, _ := contactForURN(ctx, ts.b, channel.OrgID_, channel, oldURN, "", "", clog) _ = insertContactURN(tx, newDBContactURN(channel.OrgID_, channel.ID_, NilContactID, newURN, "")) ts.NoError(tx.Commit()) @@ -703,8 +709,8 @@ func (ts *BackendTestSuite) TestMsgStatus() { oldURN, _ = urns.NewWhatsAppURN("55988776655") newURN, _ = urns.NewWhatsAppURN("5588776655") tx, _ = ts.b.db.BeginTxx(ctx, nil) - _, _ = contactForURN(ctx, ts.b, channel.OrgID_, channel, oldURN, "", "") - otherContact, _ := contactForURN(ctx, ts.b, channel.OrgID_, channel, newURN, "", "") + _, _ = contactForURN(ctx, ts.b, channel.OrgID_, channel, oldURN, "", "", clog) + otherContact, _ := contactForURN(ctx, ts.b, channel.OrgID_, channel, newURN, "", "", clog) ts.NoError(tx.Commit()) @@ -738,10 +744,11 @@ func (ts *BackendTestSuite) TestDupes() { ctx := context.Background() knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) urn, _ := urns.NewTelURNForCountry("12065551215", knChannel.Country()) msg := ts.b.NewIncomingMsg(knChannel, urn, "ping").(*DBMsg) - err := ts.b.WriteMsg(ctx, msg) + err := ts.b.WriteMsg(ctx, msg, clog) ts.NoError(err) // grab our UUID @@ -749,14 +756,14 @@ func (ts *BackendTestSuite) TestDupes() { // trying again should lead to same UUID msg = ts.b.NewIncomingMsg(knChannel, urn, "ping").(*DBMsg) - err = ts.b.WriteMsg(ctx, msg) + err = ts.b.WriteMsg(ctx, msg, clog) ts.NoError(err) ts.Equal(uuid1, msg.UUID().String()) // different message should change that msg = ts.b.NewIncomingMsg(knChannel, urn, "test").(*DBMsg) - err = ts.b.WriteMsg(ctx, msg) + err = ts.b.WriteMsg(ctx, msg, clog) ts.NoError(err) ts.NotEqual(uuid1, msg.UUID().String()) @@ -779,7 +786,7 @@ func (ts *BackendTestSuite) TestDupes() { ts.NoError(err) msg = ts.b.NewIncomingMsg(knChannel, urn, "test").(*DBMsg) - err = ts.b.WriteMsg(ctx, msg) + err = ts.b.WriteMsg(ctx, msg, clog) ts.NoError(err) ts.NotEqual(uuid2, msg.UUID().String()) @@ -1011,12 +1018,13 @@ func (ts *BackendTestSuite) TestWriteAttachment() { })) knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) urn, _ := urns.NewTelURNForCountry("12065551215", knChannel.Country()) msg := ts.b.NewIncomingMsg(knChannel, urn, "invalid attachment").(*DBMsg) msg.WithAttachment(testServer.URL) // should just end up being text/plain - err := ts.b.WriteMsg(ctx, msg) + err := ts.b.WriteMsg(ctx, msg, clog) ts.NoError(err) ts.True(strings.HasPrefix(msg.Attachments()[0], "text/plain")) @@ -1024,7 +1032,7 @@ func (ts *BackendTestSuite) TestWriteAttachment() { msg = ts.b.NewIncomingMsg(knChannel, urn, "jpg attachment").(*DBMsg) msg.WithAttachment(testServer.URL + "/test.jpg") - err = ts.b.WriteMsg(ctx, msg) + err = ts.b.WriteMsg(ctx, msg, clog) ts.NoError(err) ts.True(strings.HasPrefix(msg.Attachments()[0], "image/jpeg:")) ts.True(strings.HasSuffix(msg.Attachments()[0], ".jpg")) @@ -1033,7 +1041,7 @@ func (ts *BackendTestSuite) TestWriteAttachment() { msg = ts.b.NewIncomingMsg(knChannel, urn, "gif attachment").(*DBMsg) msg.WithAttachment(testServer.URL + "/giffy") - err = ts.b.WriteMsg(ctx, msg) + err = ts.b.WriteMsg(ctx, msg, clog) ts.NoError(err) if ts.Equal(1, len(msg.Attachments())) { ts.True(strings.HasPrefix(msg.Attachments()[0], "image/gif:")) @@ -1044,7 +1052,7 @@ func (ts *BackendTestSuite) TestWriteAttachment() { msg = ts.b.NewIncomingMsg(knChannel, urn, "png attachment").(*DBMsg) msg.WithAttachment(testServer.URL + "/header") - err = ts.b.WriteMsg(ctx, msg) + err = ts.b.WriteMsg(ctx, msg, clog) ts.NoError(err) if ts.Equal(1, len(msg.Attachments())) { ts.True(strings.HasPrefix(msg.Attachments()[0], "image/png:")) @@ -1063,6 +1071,7 @@ func (ts *BackendTestSuite) TestWriteAttachment() { func (ts *BackendTestSuite) TestWriteMsg() { ctx := context.Background() knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) // have to round to microseconds because postgres can't store nanos now := time.Now().Round(time.Microsecond).In(time.UTC) @@ -1072,7 +1081,7 @@ func (ts *BackendTestSuite) TestWriteMsg() { msg := ts.b.NewIncomingMsg(knChannel, urn, "test123").WithExternalID("ext123").WithReceivedOn(now).WithContactName("test contact").(*DBMsg) // try to write it to our db - err := ts.b.WriteMsg(ctx, msg) + err := ts.b.WriteMsg(ctx, msg, clog) ts.NoError(err) // creating the incoming msg again should give us the same UUID and have the msg set as not to write @@ -1116,7 +1125,7 @@ func (ts *BackendTestSuite) TestWriteMsg() { ts.NotNil(m.ModifiedOn_) ts.NotNil(m.QueuedOn_) - contact, err := contactForURN(ctx, ts.b, m.OrgID_, knChannel, urn, "", "") + contact, err := contactForURN(ctx, ts.b, m.OrgID_, knChannel, urn, "", "", clog) ts.Equal(null.String("test contact"), contact.Name_) ts.Equal(m.OrgID_, contact.OrgID_) ts.Equal(m.ContactID_, contact.ID_) @@ -1130,13 +1139,13 @@ func (ts *BackendTestSuite) TestWriteMsg() { // msg with null bytes in it, that's fine for a request body msg = ts.b.NewIncomingMsg(knChannel, urn, "test456\x00456").WithExternalID("ext456").(*DBMsg) - err = writeMsgToDB(ctx, ts.b, msg) + err = writeMsgToDB(ctx, ts.b, msg, clog) ts.NoError(err) // more null bytes text, _ := url.PathUnescape("%1C%00%00%00%00%00%07%E0%00") msg = ts.b.NewIncomingMsg(knChannel, urn, text).(*DBMsg) - err = writeMsgToDB(ctx, ts.b, msg) + err = writeMsgToDB(ctx, ts.b, msg, clog) ts.NoError(err) // check that our mailroom queue has an item @@ -1145,7 +1154,7 @@ func (ts *BackendTestSuite) TestWriteMsg() { rc.Do("DEL", "handler:1", "handler:active", fmt.Sprintf("c:1:%d", msg.ContactID_)) msg = ts.b.NewIncomingMsg(knChannel, urn, "hello 1 2 3").(*DBMsg) - err = writeMsgToDB(ctx, ts.b, msg) + err = writeMsgToDB(ctx, ts.b, msg, clog) ts.NoError(err) count, err := redis.Int(rc.Do("ZCARD", "handler:1")) @@ -1185,6 +1194,7 @@ func (ts *BackendTestSuite) TestWriteMsg() { func (ts *BackendTestSuite) TestPreferredChannelCheckRole() { exChannel := ts.getChannel("EX", "dbc126ed-66bc-4e28-b67b-81dc3327100a") + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, exChannel) ctx := context.Background() // have to round to microseconds because postgres can't store nanos @@ -1194,7 +1204,7 @@ func (ts *BackendTestSuite) TestPreferredChannelCheckRole() { msg := ts.b.NewIncomingMsg(exChannel, urn, "test123").WithExternalID("ext123").WithReceivedOn(now).WithContactName("test contact").(*DBMsg) // try to write it to our db - err := ts.b.WriteMsg(ctx, msg) + err := ts.b.WriteMsg(ctx, msg, clog) ts.NoError(err) time.Sleep(1 * time.Second) @@ -1216,14 +1226,15 @@ func (ts *BackendTestSuite) TestPreferredChannelCheckRole() { func (ts *BackendTestSuite) TestChannelEvent() { ctx := context.Background() - channel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) urn, _ := urns.NewTelURNForCountry("12065551616", channel.Country()) + event := ts.b.NewChannelEvent(channel, courier.Referral, urn).WithExtra(map[string]interface{}{"ref_id": "12345"}).WithContactName("kermit frog") - err := ts.b.WriteChannelEvent(ctx, event) + err := ts.b.WriteChannelEvent(ctx, event, clog) ts.NoError(err) - contact, err := contactForURN(ctx, ts.b, channel.OrgID_, channel, urn, "", "") + contact, err := contactForURN(ctx, ts.b, channel.OrgID_, channel, urn, "", "", clog) ts.NoError(err) ts.Equal(null.String("kermit frog"), contact.Name_) @@ -1258,14 +1269,16 @@ func (ts *BackendTestSuite) TestMailroomEvents() { rc.Do("FLUSHDB") channel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) urn, _ := urns.NewTelURNForCountry("12065551616", channel.Country()) + event := ts.b.NewChannelEvent(channel, courier.Referral, urn).WithExtra(map[string]interface{}{"ref_id": "12345"}). WithContactName("kermit frog"). WithOccurredOn(time.Date(2020, 8, 5, 13, 30, 0, 123456789, time.UTC)) - err := ts.b.WriteChannelEvent(ctx, event) + err := ts.b.WriteChannelEvent(ctx, event, clog) ts.NoError(err) - contact, err := contactForURN(ctx, ts.b, channel.OrgID_, channel, urn, "", "") + contact, err := contactForURN(ctx, ts.b, channel.OrgID_, channel, urn, "", "", clog) ts.NoError(err) ts.Equal(null.String("kermit frog"), contact.Name_) diff --git a/backends/rapidpro/channel_event.go b/backends/rapidpro/channel_event.go index b99d7103f..886718fde 100644 --- a/backends/rapidpro/channel_event.go +++ b/backends/rapidpro/channel_event.go @@ -69,10 +69,10 @@ func newChannelEvent(channel courier.Channel, eventType courier.ChannelEventType } // writeChannelEvent writes the passed in event to the database, queueing it to our spool in case the database is down -func writeChannelEvent(ctx context.Context, b *backend, event courier.ChannelEvent) error { +func writeChannelEvent(ctx context.Context, b *backend, event courier.ChannelEvent, clog *courier.ChannelLog) error { dbEvent := event.(*DBChannelEvent) - err := writeChannelEventToDB(ctx, b, dbEvent) + err := writeChannelEventToDB(ctx, b, dbEvent, clog) // failed writing, write to our spool instead if err != nil { @@ -94,9 +94,9 @@ RETURNING id ` // writeChannelEventToDB writes the passed in msg status to our db -func writeChannelEventToDB(ctx context.Context, b *backend, e *DBChannelEvent) error { +func writeChannelEventToDB(ctx context.Context, b *backend, e *DBChannelEvent, clog *courier.ChannelLog) error { // grab the contact for this event - contact, err := contactForURN(ctx, b, e.OrgID_, e.channel, e.URN_, "", e.ContactName_) + contact, err := contactForURN(ctx, b, e.OrgID_, e.channel, e.URN_, "", e.ContactName_, clog) if err != nil { return err } @@ -148,8 +148,11 @@ func (b *backend) flushChannelEventFile(filename string, contents []byte) error } event.channel = channel.(*DBChannel) + // create log tho it won't be written + clog := courier.NewChannelLog(courier.ChannelLogTypeMsgReceive, channel) + // try to flush to our database - return writeChannelEventToDB(ctx, b, event) + return writeChannelEventToDB(ctx, b, event, clog) } const selectEventSQL = ` diff --git a/backends/rapidpro/contact.go b/backends/rapidpro/contact.go index 2c17dd58e..3c1fef469 100644 --- a/backends/rapidpro/contact.go +++ b/backends/rapidpro/contact.go @@ -97,7 +97,7 @@ WHERE ` // contactForURN first tries to look up a contact for the passed in URN, if not finding one then creating one -func contactForURN(ctx context.Context, b *backend, org OrgID, channel *DBChannel, urn urns.URN, auth string, name string) (*DBContact, error) { +func contactForURN(ctx context.Context, b *backend, org OrgID, channel *DBChannel, urn urns.URN, auth string, name string, clog *courier.ChannelLog) (*DBContact, error) { // try to look up our contact by URN contact := &DBContact{} err := b.db.GetContext(ctx, contact, lookupContactFromURNSQL, urn.Identity(), org) @@ -139,9 +139,6 @@ func contactForURN(ctx context.Context, b *backend, org OrgID, channel *DBChanne if handler != nil { describer, isDescriber := handler.(courier.URNDescriber) if isDescriber { - // TODO: this should be created by the server and passed down - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) - atts, err := describer.DescribeURN(ctx, channel, urn, clog) // in the case of errors, we log the error but move onwards anyways @@ -193,7 +190,7 @@ func contactForURN(ctx context.Context, b *backend, org OrgID, channel *DBChanne if dbutil.IsUniqueViolation(err) { // if this was a duplicate URN, start over with a contact lookup - return contactForURN(ctx, b, org, channel, urn, auth, name) + return contactForURN(ctx, b, org, channel, urn, auth, name, clog) } return nil, errors.Wrap(err, "error getting URN for contact") } @@ -201,7 +198,7 @@ func contactForURN(ctx context.Context, b *backend, org OrgID, channel *DBChanne // we stole the URN from another contact, roll back and start over if contactURN.PrevContactID != NilContactID { tx.Rollback() - return contactForURN(ctx, b, org, channel, urn, auth, name) + return contactForURN(ctx, b, org, channel, urn, auth, name, clog) } // all is well, we created the new contact, commit and move forward diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index 6f7bad950..5a6dc74ab 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -6,6 +6,7 @@ import ( "fmt" "io/ioutil" "log" + "mime" "net/http" "net/url" "os" @@ -15,10 +16,6 @@ import ( "time" "github.com/buger/jsonparser" - "github.com/pkg/errors" - - "mime" - "github.com/gomodule/redigo/redis" "github.com/lib/pq" "github.com/nyaruka/courier" @@ -26,6 +23,7 @@ import ( "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" "github.com/nyaruka/null" + "github.com/pkg/errors" "github.com/sirupsen/logrus" filetype "gopkg.in/h2non/filetype.v1" ) @@ -51,7 +49,7 @@ const ( ) // WriteMsg creates a message given the passed in arguments -func writeMsg(ctx context.Context, b *backend, msg courier.Msg) error { +func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.ChannelLog) error { m := msg.(*DBMsg) // this msg has already been written (we received it twice), we are a no op @@ -73,7 +71,7 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg) error { } // try to write it our db - err := writeMsgToDB(ctx, b, m) + err := writeMsgToDB(ctx, b, m, clog) // fail? log if err != nil { @@ -129,9 +127,9 @@ INSERT INTO RETURNING id ` -func writeMsgToDB(ctx context.Context, b *backend, m *DBMsg) error { +func writeMsgToDB(ctx context.Context, b *backend, m *DBMsg, clog *courier.ChannelLog) error { // grab the contact for this msg - contact, err := contactForURN(ctx, b, m.OrgID_, m.channel, m.URN_, m.URNAuth_, m.ContactName_) + contact, err := contactForURN(ctx, b, m.OrgID_, m.channel, m.URN_, m.URNAuth_, m.ContactName_, clog) // our db is down, write to the spool, we will write/queue this later if err != nil { @@ -332,8 +330,11 @@ func (b *backend) flushMsgFile(filename string, contents []byte) error { } msg.channel = channel.(*DBChannel) + // create log tho it won't be written + clog := courier.NewChannelLog(courier.ChannelLogTypeMsgReceive, channel) + // try to write it our db - err = writeMsgToDB(ctx, b, msg) + err = writeMsgToDB(ctx, b, msg, clog) // fail? oh well, we'll try again later return err diff --git a/handler_test.go b/handler_test.go index 1dc2ba44a..11fa876d2 100644 --- a/handler_test.go +++ b/handler_test.go @@ -62,7 +62,7 @@ func (h *dummyHandler) receiveMsg(ctx context.Context, channel courier.Channel, msg := h.backend.NewIncomingMsg(channel, urns.URN("tel:"+from), text) w.WriteHeader(200) w.Write([]byte("ok")) - h.backend.WriteMsg(ctx, msg) + h.backend.WriteMsg(ctx, msg, clog) return []courier.Event{msg}, nil } diff --git a/handlers/africastalking/africastalking.go b/handlers/africastalking/africastalking.go index 248e79ce7..1d76d6f76 100644 --- a/handlers/africastalking/africastalking.go +++ b/handlers/africastalking/africastalking.go @@ -76,7 +76,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg := h.Backend().NewIncomingMsg(channel, urn, form.Text).WithExternalID(form.ID).WithReceivedOn(date) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } type statusForm struct { diff --git a/handlers/blackmyna/blackmyna.go b/handlers/blackmyna/blackmyna.go index 723d76d48..e553d737f 100644 --- a/handlers/blackmyna/blackmyna.go +++ b/handlers/blackmyna/blackmyna.go @@ -60,7 +60,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg := h.Backend().NewIncomingMsg(channel, urn, form.Text) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } type statusForm struct { diff --git a/handlers/bongolive/bongolive.go b/handlers/bongolive/bongolive.go index 507383430..527cb4d1b 100644 --- a/handlers/bongolive/bongolive.go +++ b/handlers/bongolive/bongolive.go @@ -99,7 +99,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg := h.Backend().NewIncomingMsg(channel, urn, form.Message).WithExternalID(form.ID).WithReceivedOn(time.Now().UTC()) // and finally queue our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } diff --git a/handlers/chikka/chikka.go b/handlers/chikka/chikka.go index f7d35d766..26f240b15 100644 --- a/handlers/chikka/chikka.go +++ b/handlers/chikka/chikka.go @@ -97,7 +97,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg := h.Backend().NewIncomingMsg(channel, urn, form.Message).WithExternalID(form.RequestID).WithReceivedOn(date) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } else { return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "unknown message_type request") } diff --git a/handlers/clickatell/clickatell.go b/handlers/clickatell/clickatell.go index 2cf8d6267..20d969a08 100644 --- a/handlers/clickatell/clickatell.go +++ b/handlers/clickatell/clickatell.go @@ -146,7 +146,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg := h.Backend().NewIncomingMsg(channel, urn, utils.CleanString(text)).WithReceivedOn(date.UTC()).WithExternalID(payload.MessageID) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // utility method to decode crazy clickatell 16 bit format diff --git a/handlers/clickmobile/clickmobile.go b/handlers/clickmobile/clickmobile.go index 9cbb09378..7267fbacc 100644 --- a/handlers/clickmobile/clickmobile.go +++ b/handlers/clickmobile/clickmobile.go @@ -80,7 +80,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg := h.Backend().NewIncomingMsg(channel, urn, payload.Text).WithExternalID(payload.ReferenceID) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } type mtPayload struct { diff --git a/handlers/dart/dart.go b/handlers/dart/dart.go index 6ee4b9b0d..ff68e5d12 100644 --- a/handlers/dart/dart.go +++ b/handlers/dart/dart.go @@ -80,7 +80,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg := h.Backend().NewIncomingMsg(channel, urn, form.Message) // and finally queue our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } type statusForm struct { diff --git a/handlers/discord/discord.go b/handlers/discord/discord.go index 8b239586b..bba5f0805 100644 --- a/handlers/discord/discord.go +++ b/handlers/discord/discord.go @@ -109,7 +109,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // WriteMsgSuccessResponse writes our response in TWIML format diff --git a/handlers/dmark/dmark.go b/handlers/dmark/dmark.go index f4b2c126b..e7890e1ca 100644 --- a/handlers/dmark/dmark.go +++ b/handlers/dmark/dmark.go @@ -71,7 +71,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg := h.Backend().NewIncomingMsg(channel, urn, form.Text).WithReceivedOn(date) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } type statusForm struct { diff --git a/handlers/external/external.go b/handlers/external/external.go index d646fe831..f5e5b5014 100644 --- a/handlers/external/external.go +++ b/handlers/external/external.go @@ -114,7 +114,7 @@ func (h *handler) receiveStopContact(ctx context.Context, channel courier.Channe // create a stop channel event channelEvent := h.Backend().NewChannelEvent(channel, courier.StopContact, urn) - err = h.Backend().WriteChannelEvent(ctx, channelEvent) + err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { return nil, err } @@ -218,7 +218,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // WriteMsgSuccessResponse writes our response in TWIML format diff --git a/handlers/facebook/facebook.go b/handlers/facebook/facebook.go index 7118a92c5..13762c571 100644 --- a/handlers/facebook/facebook.go +++ b/handlers/facebook/facebook.go @@ -282,7 +282,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } event = event.WithExtra(extra) - err := h.Backend().WriteChannelEvent(ctx, event) + err := h.Backend().WriteChannelEvent(ctx, event, clog) if err != nil { return nil, err } @@ -317,7 +317,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h event = event.WithExtra(extra) - err := h.Backend().WriteChannelEvent(ctx, event) + err := h.Backend().WriteChannelEvent(ctx, event, clog) if err != nil { return nil, err } @@ -346,7 +346,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } event = event.WithExtra(extra) - err := h.Backend().WriteChannelEvent(ctx, event) + err := h.Backend().WriteChannelEvent(ctx, event, clog) if err != nil { return nil, err } @@ -399,7 +399,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h event.WithAttachment(attURL) } - err := h.Backend().WriteMsg(ctx, event) + err := h.Backend().WriteMsg(ctx, event, clog) if err != nil { return nil, err } @@ -591,7 +591,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann clog.Error(errors.Errorf("unable to make facebook urn from %s", recipientID)) } - contact, err := h.Backend().GetContact(ctx, msg.Channel(), msg.URN(), "", "") + contact, err := h.Backend().GetContact(ctx, msg.Channel(), msg.URN(), "", "", clog) if err != nil { clog.Error(errors.Errorf("unable to get contact for %s", msg.URN().String())) } diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 871923711..c07d3ed8d 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -380,7 +380,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h var data []interface{} if channel.ChannelType() == "FBA" || channel.ChannelType() == "IG" { - events, data, err = h.processFacebookInstagramPayload(ctx, channel, payload, w, r) + events, data, err = h.processFacebookInstagramPayload(ctx, channel, payload, w, r, clog) } else { events, data, err = h.processCloudWhatsAppPayload(ctx, channel, payload, w, r, clog) @@ -475,7 +475,7 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri event.WithAttachment(mediaURL) } - err = h.Backend().WriteMsg(ctx, event) + err = h.Backend().WriteMsg(ctx, event, clog) if err != nil { return nil, nil, err } @@ -523,7 +523,7 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri return events, data, nil } -func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel courier.Channel, payload *moPayload, w http.ResponseWriter, r *http.Request) ([]courier.Event, []interface{}, error) { +func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel courier.Channel, payload *moPayload, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, []interface{}, error) { var err error // the list of events we deal with @@ -592,7 +592,7 @@ func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel c } event = event.WithExtra(extra) - err := h.Backend().WriteChannelEvent(ctx, event) + err := h.Backend().WriteChannelEvent(ctx, event, clog) if err != nil { return nil, nil, err } @@ -627,7 +627,7 @@ func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel c event = event.WithExtra(extra) - err := h.Backend().WriteChannelEvent(ctx, event) + err := h.Backend().WriteChannelEvent(ctx, event, clog) if err != nil { return nil, nil, err } @@ -656,7 +656,7 @@ func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel c } event = event.WithExtra(extra) - err := h.Backend().WriteChannelEvent(ctx, event) + err := h.Backend().WriteChannelEvent(ctx, event, clog) if err != nil { return nil, nil, err } @@ -721,7 +721,7 @@ func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel c event.WithAttachment(attURL) } - err := h.Backend().WriteMsg(ctx, event) + err := h.Backend().WriteMsg(ctx, event, clog) if err != nil { return nil, nil, err } @@ -922,7 +922,7 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, clog.Error(errors.Errorf("unable to make facebook urn from %s", recipientID)) } - contact, err := h.Backend().GetContact(ctx, msg.Channel(), msg.URN(), "", "") + contact, err := h.Backend().GetContact(ctx, msg.Channel(), msg.URN(), "", "", clog) if err != nil { clog.Error(errors.Errorf("unable to get contact for %s", msg.URN().String())) } diff --git a/handlers/firebase/firebase.go b/handlers/firebase/firebase.go index 82e276fed..fc7e1e7f7 100644 --- a/handlers/firebase/firebase.go +++ b/handlers/firebase/firebase.go @@ -79,7 +79,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w dbMsg := h.Backend().NewIncomingMsg(channel, urn, form.Msg).WithReceivedOn(date).WithContactName(form.Name).WithURNAuth(form.FCMToken) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{dbMsg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{dbMsg}, w, r, clog) } type registerForm struct { @@ -103,7 +103,7 @@ func (h *handler) registerContact(ctx context.Context, channel courier.Channel, } // create our contact - contact, err := h.Backend().GetContact(ctx, channel, urn, form.FCMToken, form.Name) + contact, err := h.Backend().GetContact(ctx, channel, urn, form.FCMToken, form.Name, clog) if err != nil { return nil, err } diff --git a/handlers/freshchat/freshchat.go b/handlers/freshchat/freshchat.go index 7d28ee7dd..0ba4ee032 100644 --- a/handlers/freshchat/freshchat.go +++ b/handlers/freshchat/freshchat.go @@ -98,7 +98,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg.WithAttachment(mediaURL) } // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { diff --git a/handlers/generic.go b/handlers/generic.go index 3793cadf4..2ee529147 100644 --- a/handlers/generic.go +++ b/handlers/generic.go @@ -29,7 +29,7 @@ func NewTelReceiveHandler(h *BaseHandler, fromField string, bodyField string) co } // build our msg msg := h.Backend().NewIncomingMsg(c, urn, body).WithReceivedOn(time.Now().UTC()) - return WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } } diff --git a/handlers/globe/globe.go b/handlers/globe/globe.go index d4b02cff9..29e4e998a 100644 --- a/handlers/globe/globe.go +++ b/handlers/globe/globe.go @@ -107,7 +107,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. msgs = append(msgs, msg) } - return handlers.WriteMsgsAndResponse(ctx, h, msgs, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, msgs, w, r, clog) } // { diff --git a/handlers/highconnection/highconnection.go b/handlers/highconnection/highconnection.go index c5f058be1..278faeec0 100644 --- a/handlers/highconnection/highconnection.go +++ b/handlers/highconnection/highconnection.go @@ -77,7 +77,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg := h.Backend().NewIncomingMsg(channel, urn, utils.CleanString(text)).WithReceivedOn(date.UTC()) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } type statusForm struct { diff --git a/handlers/hormuud/hormuud.go b/handlers/hormuud/hormuud.go index 6da7ec3b9..c41a5b494 100644 --- a/handlers/hormuud/hormuud.go +++ b/handlers/hormuud/hormuud.go @@ -67,7 +67,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. } msg := h.Backend().NewIncomingMsg(c, urn, payload.MessageText).WithReceivedOn(date) - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } type mtPayload struct { diff --git a/handlers/i2sms/i2sms.go b/handlers/i2sms/i2sms.go index 21febb54d..458f4b0d1 100644 --- a/handlers/i2sms/i2sms.go +++ b/handlers/i2sms/i2sms.go @@ -62,7 +62,7 @@ func (h *handler) receive(ctx context.Context, c courier.Channel, w http.Respons // build our msg msg := h.Backend().NewIncomingMsg(c, urn, body).WithReceivedOn(time.Now().UTC()) - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // { diff --git a/handlers/infobip/infobip.go b/handlers/infobip/infobip.go index 1e14686d0..c137f7e69 100644 --- a/handlers/infobip/infobip.go +++ b/handlers/infobip/infobip.go @@ -171,7 +171,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring request, no message") } - return handlers.WriteMsgsAndResponse(ctx, h, msgs, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, msgs, w, r, clog) } // Send sends the given message, logging any HTTP calls or errors diff --git a/handlers/jasmin/jasmin.go b/handlers/jasmin/jasmin.go index 962cf4f77..825d951e5 100644 --- a/handlers/jasmin/jasmin.go +++ b/handlers/jasmin/jasmin.go @@ -97,7 +97,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. msg := h.Backend().NewIncomingMsg(c, urn, text).WithExternalID(form.ID).WithReceivedOn(time.Now().UTC()) // and finally queue our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error { diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 30fb0b692..82635c519 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -130,7 +130,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w if payload.MsgType == "event" && payload.Event == "subscribe" { channelEvent := h.Backend().NewChannelEvent(channel, courier.NewConversation, urn) - err := h.Backend().WriteChannelEvent(ctx, channelEvent) + err := h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { return nil, err } @@ -151,7 +151,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } func buildMediaURL(mediaID string) string { diff --git a/handlers/junebug/junebug.go b/handlers/junebug/junebug.go index 2d27a12d8..b5873ceb2 100644 --- a/handlers/junebug/junebug.go +++ b/handlers/junebug/junebug.go @@ -86,7 +86,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. msg := h.Backend().NewIncomingMsg(c, urn, payload.Content).WithExternalID(payload.MessageID).WithReceivedOn(date.UTC()) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // { diff --git a/handlers/kaleyra/kaleyra.go b/handlers/kaleyra/kaleyra.go index 39c0f09cf..ed1f5de91 100644 --- a/handlers/kaleyra/kaleyra.go +++ b/handlers/kaleyra/kaleyra.go @@ -102,7 +102,7 @@ func (h *handler) receiveMsg(ctx context.Context, channel courier.Channel, w htt } // write msg - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } var statusMapping = map[string]courier.MsgStatusValue{ diff --git a/handlers/kannel/kannel.go b/handlers/kannel/kannel.go index d636f8203..e5b7d7d49 100644 --- a/handlers/kannel/kannel.go +++ b/handlers/kannel/kannel.go @@ -77,7 +77,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg := h.Backend().NewIncomingMsg(channel, urn, form.Message).WithExternalID(form.ID).WithReceivedOn(date) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } var statusMapping = map[int]courier.MsgStatusValue{ diff --git a/handlers/line/line.go b/handlers/line/line.go index 8219dd6c2..21bf6e23c 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -174,7 +174,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring request, no message") } - return handlers.WriteMsgsAndResponse(ctx, h, msgs, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, msgs, w, r, clog) } diff --git a/handlers/m3tech/m3tech.go b/handlers/m3tech/m3tech.go index e6a297c7f..d7499fb54 100644 --- a/handlers/m3tech/m3tech.go +++ b/handlers/m3tech/m3tech.go @@ -58,7 +58,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. // build our msg msg := h.Backend().NewIncomingMsg(c, urn, body).WithReceivedOn(time.Now().UTC()) - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // WriteMsgSuccessResponse writes a success response for the messages diff --git a/handlers/macrokiosk/macrokiosk.go b/handlers/macrokiosk/macrokiosk.go index 323e567be..2e4eb892f 100644 --- a/handlers/macrokiosk/macrokiosk.go +++ b/handlers/macrokiosk/macrokiosk.go @@ -131,7 +131,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg := h.Backend().NewIncomingMsg(channel, urn, form.Text).WithExternalID(form.MsgID).WithReceivedOn(date.UTC()) // and write it - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // WriteMsgSuccessResponse diff --git a/handlers/mblox/mblox.go b/handlers/mblox/mblox.go index a2c6d04e1..ecf2332f3 100644 --- a/handlers/mblox/mblox.go +++ b/handlers/mblox/mblox.go @@ -101,7 +101,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h msg := h.Backend().NewIncomingMsg(channel, urn, payload.Body).WithReceivedOn(date.UTC()).WithExternalID(payload.ID) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, fmt.Errorf("not handled, unknown type: %s", payload.Type)) diff --git a/handlers/mtarget/mtarget.go b/handlers/mtarget/mtarget.go index f2d9c1dfd..bf8f62482 100644 --- a/handlers/mtarget/mtarget.go +++ b/handlers/mtarget/mtarget.go @@ -134,7 +134,7 @@ func (h *handler) receiveMsg(ctx context.Context, c courier.Channel, w http.Resp // if this a stop command, shortcut stopping that contact if keyword == "Stop" { stop := h.Backend().NewChannelEvent(c, courier.StopContact, urn) - err := h.Backend().WriteChannelEvent(ctx, stop) + err := h.Backend().WriteChannelEvent(ctx, stop, clog) if err != nil { return nil, err } @@ -144,7 +144,7 @@ func (h *handler) receiveMsg(ctx context.Context, c courier.Channel, w http.Resp // otherwise, create our incoming message and write that msg := h.Backend().NewIncomingMsg(c, urn, text).WithReceivedOn(time.Now().UTC()) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // Send sends the given message, logging any HTTP calls or errors diff --git a/handlers/nexmo/nexmo.go b/handlers/nexmo/nexmo.go index 602d78fbb..28b89f7fe 100644 --- a/handlers/nexmo/nexmo.go +++ b/handlers/nexmo/nexmo.go @@ -113,7 +113,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w // build our msg msg := h.Backend().NewIncomingMsg(channel, urn, form.Text) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // Send sends the given message, logging any HTTP calls or errors diff --git a/handlers/novo/novo.go b/handlers/novo/novo.go index 095ea5c73..7c8848f5d 100644 --- a/handlers/novo/novo.go +++ b/handlers/novo/novo.go @@ -74,7 +74,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. // build our msg msg := h.Backend().NewIncomingMsg(c, urn, body).WithReceivedOn(time.Now().UTC()) - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // Send sends the given message, logging any HTTP calls or errors diff --git a/handlers/playmobile/playmobile.go b/handlers/playmobile/playmobile.go index 63edeeb20..e3d8256eb 100644 --- a/handlers/playmobile/playmobile.go +++ b/handlers/playmobile/playmobile.go @@ -141,7 +141,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. } // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, msgs, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, msgs, w, r, clog) } // Send sends the given message, logging any HTTP calls or errors diff --git a/handlers/plivo/plivo.go b/handlers/plivo/plivo.go index 0509db49e..1d9f7ce44 100644 --- a/handlers/plivo/plivo.go +++ b/handlers/plivo/plivo.go @@ -124,7 +124,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w // build our msg msg := h.Backend().NewIncomingMsg(channel, urn, form.Text).WithExternalID(form.MessageUUID) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } type mtPayload struct { diff --git a/handlers/responses.go b/handlers/responses.go index f0ecf71d0..119fa60cb 100644 --- a/handlers/responses.go +++ b/handlers/responses.go @@ -17,10 +17,10 @@ type ResponseWriter interface { } // WriteMsgsAndResponse writes the passed in message to our backend -func WriteMsgsAndResponse(ctx context.Context, h ResponseWriter, msgs []courier.Msg, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func WriteMsgsAndResponse(ctx context.Context, h ResponseWriter, msgs []courier.Msg, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { events := make([]courier.Event, len(msgs), len(msgs)) for i, m := range msgs { - err := h.Backend().WriteMsg(ctx, m) + err := h.Backend().WriteMsg(ctx, m, clog) if err != nil { return nil, err } diff --git a/handlers/rocketchat/rocketchat.go b/handlers/rocketchat/rocketchat.go index 17e080567..11ae3ca2a 100644 --- a/handlers/rocketchat/rocketchat.go +++ b/handlers/rocketchat/rocketchat.go @@ -85,7 +85,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg.WithAttachment(attachment.URL) } - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // BuildDownloadMediaRequest download media for message attachment with RC auth_token/user_id set diff --git a/handlers/shaqodoon/shaqodoon.go b/handlers/shaqodoon/shaqodoon.go index 4999ab175..20edb24fc 100644 --- a/handlers/shaqodoon/shaqodoon.go +++ b/handlers/shaqodoon/shaqodoon.go @@ -80,7 +80,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w // build our msg msg := h.Backend().NewIncomingMsg(channel, urn, form.Text).WithReceivedOn(date) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // Send sends the given message, logging any HTTP calls or errors diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index a172f6fee..778e2680e 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -100,7 +100,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h msg.WithAttachment(attURL) } - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "Ignoring request, no message") } diff --git a/handlers/smscentral/smscentral.go b/handlers/smscentral/smscentral.go index e28fb57da..87d7ffbec 100644 --- a/handlers/smscentral/smscentral.go +++ b/handlers/smscentral/smscentral.go @@ -59,7 +59,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w // build our msg msg := h.Backend().NewIncomingMsg(channel, urn, form.Message) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // Send sends the given message, logging any HTTP calls or errors diff --git a/handlers/start/start.go b/handlers/start/start.go index bbd7c2c17..738ef1d94 100644 --- a/handlers/start/start.go +++ b/handlers/start/start.go @@ -84,7 +84,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg := h.Backend().NewIncomingMsg(channel, urn, payload.Body.Text).WithReceivedOn(date) // and write it - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // Start Mobile expects a XML response from a message receive request diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index fcfb82fff..4f6127bf7 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -79,7 +79,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w // this is a start command, trigger a new conversation if text == "/start" { event := h.Backend().NewChannelEvent(channel, courier.NewConversation, urn).WithContactName(name).WithOccurredOn(date) - err = h.Backend().WriteChannelEvent(ctx, event) + err = h.Backend().WriteChannelEvent(ctx, event, clog) if err != nil { return nil, err } @@ -137,7 +137,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg.WithAttachment(mediaURL) } // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } type mtResponse struct { @@ -231,7 +231,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann if botBlocked { status.SetStatus(courier.MsgFailed) channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) - err = h.Backend().WriteChannelEvent(ctx, channelEvent) + err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) return status, err } status.SetExternalID(externalID) @@ -257,7 +257,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann if botBlocked { status.SetStatus(courier.MsgFailed) channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) - err = h.Backend().WriteChannelEvent(ctx, channelEvent) + err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) return status, err } status.SetExternalID(externalID) @@ -273,7 +273,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann if botBlocked { status.SetStatus(courier.MsgFailed) channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) - err = h.Backend().WriteChannelEvent(ctx, channelEvent) + err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) return status, err } status.SetExternalID(externalID) @@ -289,7 +289,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann if botBlocked { status.SetStatus(courier.MsgFailed) channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) - err = h.Backend().WriteChannelEvent(ctx, channelEvent) + err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) return status, err } status.SetExternalID(externalID) @@ -305,7 +305,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann if botBlocked { status.SetStatus(courier.MsgFailed) channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) - err = h.Backend().WriteChannelEvent(ctx, channelEvent) + err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) return status, err } status.SetExternalID(externalID) diff --git a/handlers/telesom/telesom.go b/handlers/telesom/telesom.go index eac867620..c614704a1 100644 --- a/handlers/telesom/telesom.go +++ b/handlers/telesom/telesom.go @@ -60,7 +60,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w dbMsg := h.Backend().NewIncomingMsg(channel, urn, form.Message) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{dbMsg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{dbMsg}, w, r, clog) } diff --git a/handlers/test.go b/handlers/test.go index bb5f22acb..bec3cbbcf 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -316,7 +316,7 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour if tc.ExpectedContactURNs != nil { var contactUUID courier.ContactUUID for urn, shouldBePresent := range tc.ExpectedContactURNs { - contact, _ := mb.GetContact(ctx, channel, urns.URN(urn), "", "") + contact, _ := mb.GetContact(ctx, channel, urns.URN(urn), "", "", clog) if contactUUID == courier.NilContactUUID && shouldBePresent { contactUUID = contact.UUID() } diff --git a/handlers/thinq/thinq.go b/handlers/thinq/thinq.go index 119a5cba5..9f16d55ef 100644 --- a/handlers/thinq/thinq.go +++ b/handlers/thinq/thinq.go @@ -77,7 +77,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } else { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, fmt.Errorf("unknown message type: %s", form.Type)) } - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // guid: thinQ guid returned when an outbound message is sent via our API diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index 855e5ad6f..5cf859c92 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -136,7 +136,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w mediaURL := r.PostForm.Get(fmt.Sprintf("MediaUrl%d", i)) msg.WithAttachment(mediaURL) } - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // receiveStatus is our HTTP handler function for status updates @@ -189,7 +189,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w // create a stop channel event channelEvent := h.Backend().NewChannelEvent(channel, courier.StopContact, urn) - err = h.Backend().WriteChannelEvent(ctx, channelEvent) + err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { return nil, err } @@ -280,7 +280,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // create a stop channel event channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) - err = h.Backend().WriteChannelEvent(ctx, channelEvent) + err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { return nil, err } diff --git a/handlers/twitter/twitter.go b/handlers/twitter/twitter.go index f521edf80..4deec7983 100644 --- a/handlers/twitter/twitter.go +++ b/handlers/twitter/twitter.go @@ -201,7 +201,7 @@ func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.Re msgs = append(msgs, msg) } - return handlers.WriteMsgsAndResponse(ctx, h, msgs, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, msgs, w, r, clog) } // { diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index f1ddfbab7..e4549b12c 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -123,7 +123,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h // build the channel event channelEvent := h.Backend().NewChannelEvent(channel, courier.WelcomeMessage, urn).WithContactName(ContactName) - err = h.Backend().WriteChannelEvent(ctx, channelEvent) + err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } @@ -143,7 +143,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h // build the channel event channelEvent := h.Backend().NewChannelEvent(channel, courier.NewConversation, urn).WithContactName(ContactName) - err = h.Backend().WriteChannelEvent(ctx, channelEvent) + err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { return nil, err } @@ -161,7 +161,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h // build the channel event channelEvent := h.Backend().NewChannelEvent(channel, courier.StopContact, urn) - err = h.Backend().WriteChannelEvent(ctx, channelEvent) + err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { return nil, err } @@ -232,7 +232,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h msg.WithAttachment(mediaURL) } // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } return nil, courier.WriteError(ctx, w, r, fmt.Errorf("not handled, unknown event: %s", event)) diff --git a/handlers/vk/vk.go b/handlers/vk/vk.go index 9e8cd9f6c..d80e666fb 100644 --- a/handlers/vk/vk.go +++ b/handlers/vk/vk.go @@ -224,7 +224,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h if err := handlers.DecodeAndValidateJSON(newMessage, r); err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } - return h.receiveMessage(ctx, channel, w, r, newMessage) + return h.receiveMessage(ctx, channel, w, r, newMessage, clog) default: return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring request, no message or server verification event") @@ -241,7 +241,7 @@ func (h *handler) verifyServer(channel courier.Channel, w http.ResponseWriter) ( } // receiveMessage handles new message event -func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, payload *moNewMessagePayload) ([]courier.Event, error) { +func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, payload *moNewMessagePayload, clog *courier.ChannelLog) ([]courier.Event, error) { userId := payload.Object.Message.UserId urn, err := urns.NewURNFromParts(urns.VKScheme, strconv.FormatInt(userId, 10), "", "") @@ -262,7 +262,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, errors.New("no text or attachment")) } // save message to our backend - if err := h.Backend().WriteMsg(ctx, event); err != nil { + if err := h.Backend().WriteMsg(ctx, event, clog); err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } h.Backend().WriteExternalIDSeen(event) diff --git a/handlers/wavy/wavy.go b/handlers/wavy/wavy.go index c069641df..2a7e83ef6 100644 --- a/handlers/wavy/wavy.go +++ b/handlers/wavy/wavy.go @@ -129,7 +129,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w msg := h.Backend().NewIncomingMsg(channel, urn, payload.Message).WithExternalID(payload.ID).WithReceivedOn(date.UTC()) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index 625c62e45..8e8af96c6 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -189,7 +189,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w if payload.MsgType == "event" && payload.Event == "subscribe" { channelEvent := h.Backend().NewChannelEvent(channel, courier.NewConversation, urn) - err := h.Backend().WriteChannelEvent(ctx, channelEvent) + err := h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { return nil, err } @@ -210,7 +210,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // WriteMsgSuccessResponse writes our response diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index 2aa180c9d..1ebb70195 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -250,7 +250,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h event.WithAttachment(mediaURL) } - err = h.Backend().WriteMsg(ctx, event) + err = h.Backend().WriteMsg(ctx, event, clog) if err != nil { return nil, err } diff --git a/handlers/yo/yo.go b/handlers/yo/yo.go index cddb0460a..f1ab64cbb 100644 --- a/handlers/yo/yo.go +++ b/handlers/yo/yo.go @@ -93,7 +93,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w dbMsg := h.Backend().NewIncomingMsg(channel, urn, form.Message).WithReceivedOn(date) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{dbMsg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{dbMsg}, w, r, clog) } // Send sends the given message, logging any HTTP calls or errors @@ -144,7 +144,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // create a stop channel event channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) - err = h.Backend().WriteChannelEvent(ctx, channelEvent) + err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { return nil, err } diff --git a/handlers/zenvia/zenvia.go b/handlers/zenvia/zenvia.go index d6922cbc9..da6dd822e 100644 --- a/handlers/zenvia/zenvia.go +++ b/handlers/zenvia/zenvia.go @@ -134,7 +134,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // and finally write our messages - return handlers.WriteMsgsAndResponse(ctx, h, msgs, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, msgs, w, r, clog) } var statusMapping = map[string]courier.MsgStatusValue{ diff --git a/handlers/zenviaold/zenviaold.go b/handlers/zenviaold/zenviaold.go index 06636608f..fa2e90847 100644 --- a/handlers/zenviaold/zenviaold.go +++ b/handlers/zenviaold/zenviaold.go @@ -139,7 +139,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w // build our msg msg := h.Backend().NewIncomingMsg(channel, urn, payload.CallbackMORequest.Text).WithExternalID(payload.CallbackMORequest.ID).WithReceivedOn(date.UTC()) // and finally write our message - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } // receiveStatus is our HTTP handler function for status updates diff --git a/test/backend.go b/test/backend.go index e2621ac70..c3a1d3e6f 100644 --- a/test/backend.go +++ b/test/backend.go @@ -190,7 +190,7 @@ func (mb *MockBackend) SetErrorOnQueue(shouldError bool) { } // WriteMsg queues the passed in message internally -func (mb *MockBackend) WriteMsg(ctx context.Context, m courier.Msg) error { +func (mb *MockBackend) WriteMsg(ctx context.Context, m courier.Msg, clog *courier.ChannelLog) error { mock := m.(*mockMsg) // this msg has already been written (we received it twice), we are a no op @@ -249,7 +249,7 @@ func (mb *MockBackend) NewChannelEvent(channel courier.Channel, eventType courie } // WriteChannelEvent writes the channel event passed in -func (mb *MockBackend) WriteChannelEvent(ctx context.Context, event courier.ChannelEvent) error { +func (mb *MockBackend) WriteChannelEvent(ctx context.Context, event courier.ChannelEvent, clog *courier.ChannelLog) error { mb.mutex.Lock() defer mb.mutex.Unlock() @@ -277,7 +277,7 @@ func (mb *MockBackend) GetChannelByAddress(ctx context.Context, cType courier.Ch } // GetContact creates a new contact with the passed in channel and URN -func (mb *MockBackend) GetContact(ctx context.Context, channel courier.Channel, urn urns.URN, auth string, name string) (courier.Contact, error) { +func (mb *MockBackend) GetContact(ctx context.Context, channel courier.Channel, urn urns.URN, auth, name string, clog *courier.ChannelLog) (courier.Contact, error) { contact, found := mb.contacts[urn] if !found { uuid, _ := courier.NewContactUUID(string(uuids.New())) From b9841f3840e1c5c95e8c29634028d28365f78646 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 25 Aug 2022 19:47:11 -0500 Subject: [PATCH 110/294] WIP --- backends/rapidpro/backend_test.go | 26 ++++++++++++------------ backends/rapidpro/channel_event.go | 2 +- backends/rapidpro/msg.go | 2 +- channel_log.go | 23 +++++++++++++-------- channel_log_test.go | 2 +- handler.go | 2 +- handler_test.go | 8 ++++---- handlers/base.go | 2 +- handlers/facebook/facebook.go | 2 +- handlers/facebook/facebook_test.go | 2 +- handlers/facebookapp/facebookapp.go | 2 +- handlers/facebookapp/facebookapp_test.go | 6 +++--- handlers/http_test.go | 2 +- handlers/jiochat/jiochat.go | 2 +- handlers/jiochat/jiochat_test.go | 2 +- handlers/slack/slack_test.go | 2 +- handlers/test.go | 2 +- handlers/vk/vk_test.go | 2 +- handlers/wechat/wechat.go | 2 +- handlers/wechat/wechat_test.go | 2 +- sender.go | 2 +- server.go | 2 +- 22 files changed, 52 insertions(+), 47 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index ebee01da9..e0b0459a8 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -246,7 +246,7 @@ func (ts *BackendTestSuite) TestDeleteMsgWithExternalID() { func (ts *BackendTestSuite) TestContact() { knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel, nil) urn, _ := urns.NewTelURNForCountry("12065551518", "US") ctx := context.Background() @@ -294,7 +294,7 @@ func (ts *BackendTestSuite) TestContact() { func (ts *BackendTestSuite) TestContactRace() { knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel, nil) urn, _ := urns.NewTelURNForCountry("12065551518", "US") urnSleep = true @@ -322,7 +322,7 @@ func (ts *BackendTestSuite) TestContactRace() { func (ts *BackendTestSuite) TestAddAndRemoveContactURN() { knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel, nil) ctx := context.Background() cURN, err := urns.NewTelURNForCountry("+12067799192", "US") @@ -365,7 +365,7 @@ func (ts *BackendTestSuite) TestAddAndRemoveContactURN() { func (ts *BackendTestSuite) TestContactURN() { knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") twChannel := ts.getChannel("TW", "dbc126ed-66bc-4e28-b67b-81dc3327c96a") - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel, nil) urn, _ := urns.NewTelURNForCountry("12065551515", "US") ctx := context.Background() @@ -470,7 +470,7 @@ func (ts *BackendTestSuite) TestContactURNPriority() { twChannel := ts.getChannel("TW", "dbc126ed-66bc-4e28-b67b-81dc3327c96a") knURN, _ := urns.NewTelURNForCountry("12065551111", "US") twURN, _ := urns.NewTelURNForCountry("12065552222", "US") - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel, nil) ctx := context.Background() @@ -509,7 +509,7 @@ func (ts *BackendTestSuite) TestContactURNPriority() { func (ts *BackendTestSuite) TestMsgStatus() { ctx := context.Background() channel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, nil) now := time.Now().In(time.UTC) time.Sleep(2 * time.Millisecond) @@ -744,7 +744,7 @@ func (ts *BackendTestSuite) TestDupes() { ctx := context.Background() knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel, nil) urn, _ := urns.NewTelURNForCountry("12065551215", knChannel.Country()) msg := ts.b.NewIncomingMsg(knChannel, urn, "ping").(*DBMsg) @@ -979,7 +979,7 @@ func (ts *BackendTestSuite) TestWriteChanneLog() { trace, err := httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) ts.NoError(err) - clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel, nil) clog.HTTP(trace) err = ts.b.WriteChannelLog(ctx, clog) @@ -1018,7 +1018,7 @@ func (ts *BackendTestSuite) TestWriteAttachment() { })) knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel, nil) urn, _ := urns.NewTelURNForCountry("12065551215", knChannel.Country()) msg := ts.b.NewIncomingMsg(knChannel, urn, "invalid attachment").(*DBMsg) msg.WithAttachment(testServer.URL) @@ -1071,7 +1071,7 @@ func (ts *BackendTestSuite) TestWriteAttachment() { func (ts *BackendTestSuite) TestWriteMsg() { ctx := context.Background() knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel, nil) // have to round to microseconds because postgres can't store nanos now := time.Now().Round(time.Microsecond).In(time.UTC) @@ -1194,7 +1194,7 @@ func (ts *BackendTestSuite) TestWriteMsg() { func (ts *BackendTestSuite) TestPreferredChannelCheckRole() { exChannel := ts.getChannel("EX", "dbc126ed-66bc-4e28-b67b-81dc3327100a") - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, exChannel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, exChannel, nil) ctx := context.Background() // have to round to microseconds because postgres can't store nanos @@ -1227,7 +1227,7 @@ func (ts *BackendTestSuite) TestPreferredChannelCheckRole() { func (ts *BackendTestSuite) TestChannelEvent() { ctx := context.Background() channel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, nil) urn, _ := urns.NewTelURNForCountry("12065551616", channel.Country()) event := ts.b.NewChannelEvent(channel, courier.Referral, urn).WithExtra(map[string]interface{}{"ref_id": "12345"}).WithContactName("kermit frog") @@ -1269,7 +1269,7 @@ func (ts *BackendTestSuite) TestMailroomEvents() { rc.Do("FLUSHDB") channel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, nil) urn, _ := urns.NewTelURNForCountry("12065551616", channel.Country()) event := ts.b.NewChannelEvent(channel, courier.Referral, urn).WithExtra(map[string]interface{}{"ref_id": "12345"}). diff --git a/backends/rapidpro/channel_event.go b/backends/rapidpro/channel_event.go index 886718fde..56e51c2a8 100644 --- a/backends/rapidpro/channel_event.go +++ b/backends/rapidpro/channel_event.go @@ -149,7 +149,7 @@ func (b *backend) flushChannelEventFile(filename string, contents []byte) error event.channel = channel.(*DBChannel) // create log tho it won't be written - clog := courier.NewChannelLog(courier.ChannelLogTypeMsgReceive, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeMsgReceive, channel, nil) // try to flush to our database return writeChannelEventToDB(ctx, b, event, clog) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index 5a6dc74ab..638d20b3e 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -331,7 +331,7 @@ func (b *backend) flushMsgFile(filename string, contents []byte) error { msg.channel = channel.(*DBChannel) // create log tho it won't be written - clog := courier.NewChannelLog(courier.ChannelLogTypeMsgReceive, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeMsgReceive, channel, nil) // try to write it our db err = writeMsgToDB(ctx, b, msg, clog) diff --git a/channel_log.go b/channel_log.go index 2c68d5218..f6f8fb909 100644 --- a/channel_log.go +++ b/channel_log.go @@ -5,6 +5,7 @@ import ( "github.com/nyaruka/gocommon/dates" "github.com/nyaruka/gocommon/httpx" + "github.com/nyaruka/gocommon/stringsx" "github.com/nyaruka/gocommon/uuids" ) @@ -44,30 +45,32 @@ type ChannelLog struct { type_ ChannelLogType channel Channel msgID MsgID - recorder *httpx.Recorder httpLogs []*httpx.Log errors []ChannelError createdOn time.Time elapsed time.Duration + + recorder *httpx.Recorder + redactor stringsx.Redactor } // NewChannelLogForIncoming creates a new channel log for an incoming request, the type of which won't be known // until the handler completes. -func NewChannelLogForIncoming(r *httpx.Recorder, ch Channel) *ChannelLog { - return newChannelLog(ChannelLogTypeUnknown, ch, r, NilMsgID) +func NewChannelLogForIncoming(ch Channel, r *httpx.Recorder, redactVals []string) *ChannelLog { + return newChannelLog(ChannelLogTypeUnknown, ch, r, NilMsgID, redactVals) } // NewChannelLogForSend creates a new channel log for a message send -func NewChannelLogForSend(msg Msg) *ChannelLog { - return newChannelLog(ChannelLogTypeMsgSend, msg.Channel(), nil, msg.ID()) +func NewChannelLogForSend(msg Msg, redactVals []string) *ChannelLog { + return newChannelLog(ChannelLogTypeMsgSend, msg.Channel(), nil, msg.ID(), redactVals) } // NewChannelLog creates a new channel log with the given type and channel -func NewChannelLog(t ChannelLogType, ch Channel) *ChannelLog { - return newChannelLog(t, ch, nil, NilMsgID) +func NewChannelLog(t ChannelLogType, ch Channel, redactVals []string) *ChannelLog { + return newChannelLog(t, ch, nil, NilMsgID, redactVals) } -func newChannelLog(t ChannelLogType, ch Channel, r *httpx.Recorder, mid MsgID) *ChannelLog { +func newChannelLog(t ChannelLogType, ch Channel, r *httpx.Recorder, mid MsgID, redactVals []string) *ChannelLog { return &ChannelLog{ uuid: uuids.New(), type_: t, @@ -75,6 +78,8 @@ func newChannelLog(t ChannelLogType, ch Channel, r *httpx.Recorder, mid MsgID) * recorder: r, msgID: mid, createdOn: dates.Now(), + + redactor: stringsx.NewRedactor("**********", redactVals...), } } @@ -137,5 +142,5 @@ func (l *ChannelLog) Elapsed() time.Duration { } func (l *ChannelLog) traceToLog(t *httpx.Trace) *httpx.Log { - return httpx.NewLog(t, 2048, 50000, nil) + return httpx.NewLog(t, 2048, 50000, l.redactor) } diff --git a/channel_log_test.go b/channel_log_test.go index 84e35ad9f..2ec254883 100644 --- a/channel_log_test.go +++ b/channel_log_test.go @@ -26,7 +26,7 @@ func TestChannelLog(t *testing.T) { defer uuids.SetGenerator(uuids.DefaultGenerator) channel := test.NewMockChannel("fef91e9b-a6ed-44fb-b6ce-feed8af585a8", "NX", "1234", "US", nil) - clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel, nil) // make a request that will have a response req, _ := http.NewRequest("POST", "https://api.messages.com/send.json", nil) diff --git a/handler.go b/handler.go index c1406c809..3d99908a8 100644 --- a/handler.go +++ b/handler.go @@ -24,7 +24,7 @@ type ChannelHandler interface { ChannelType() ChannelType ChannelName() string UseChannelRouteUUID() bool - RedactValues() []string + RedactValues(Channel) []string GetChannel(context.Context, *http.Request) (Channel, error) Send(context.Context, Msg, *ChannelLog) (MsgStatus, error) } diff --git a/handler_test.go b/handler_test.go index a27bcd560..59dd69561 100644 --- a/handler_test.go +++ b/handler_test.go @@ -28,10 +28,10 @@ func NewHandler() courier.ChannelHandler { return &dummyHandler{} } -func (h *dummyHandler) ChannelName() string { return "Dummy Handler" } -func (h *dummyHandler) ChannelType() courier.ChannelType { return courier.ChannelType("DM") } -func (h *dummyHandler) UseChannelRouteUUID() bool { return true } -func (h *dummyHandler) RedactValues() []string { return []string{"sesame"} } +func (h *dummyHandler) ChannelName() string { return "Dummy Handler" } +func (h *dummyHandler) ChannelType() courier.ChannelType { return courier.ChannelType("DM") } +func (h *dummyHandler) UseChannelRouteUUID() bool { return true } +func (h *dummyHandler) RedactValues(courier.Channel) []string { return []string{"sesame"} } func (h *dummyHandler) GetChannel(ctx context.Context, r *http.Request) (courier.Channel, error) { dmChannel := test.NewMockChannel("e4bb1578-29da-4fa5-a214-9da19dd24230", "DM", "2020", "US", map[string]interface{}{}) diff --git a/handlers/base.go b/handlers/base.go index 3d867d2d2..c9afb581c 100644 --- a/handlers/base.go +++ b/handlers/base.go @@ -58,7 +58,7 @@ func (h *BaseHandler) UseChannelRouteUUID() bool { return h.useChannelRouteUUID } -func (h *BaseHandler) RedactValues() []string { return nil } +func (h *BaseHandler) RedactValues(courier.Channel) []string { return nil } // GetChannel returns the channel func (h *BaseHandler) GetChannel(ctx context.Context, r *http.Request) (courier.Channel, error) { diff --git a/handlers/facebook/facebook.go b/handlers/facebook/facebook.go index 13762c571..0c6e69937 100644 --- a/handlers/facebook/facebook.go +++ b/handlers/facebook/facebook.go @@ -111,7 +111,7 @@ func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w } func (h *handler) subscribeToEvents(ctx context.Context, channel courier.Channel, authToken string) { - clog := courier.NewChannelLog(courier.ChannelLogTypePageSubscribe, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypePageSubscribe, channel, h.RedactValues(channel)) // subscribe to messaging events for this page form := url.Values{} diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index cc9ed5c28..d08c82a6d 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -495,7 +495,7 @@ func TestDescribe(t *testing.T) { channel := testChannels[0] handler := newHandler().(courier.URNDescriber) - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, nil) tcs := []struct { urn urns.URN diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index c950a812f..56d81374e 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -265,7 +265,7 @@ type moPayload struct { } `json:"entry"` } -func (h *handler) RedactValues() []string { +func (h *handler) RedactValues(ch courier.Channel) []string { return []string{ h.Server().Config().FacebookApplicationSecret, h.Server().Config().FacebookWebhookSecret, diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 2657f0a30..ff0319a57 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -191,7 +191,7 @@ func TestDescribeFBA(t *testing.T) { channel := testChannelsFBA[0] handler := newHandler("FBA", "Facebook", false).(courier.URNDescriber) - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, nil) tcs := []struct { urn urns.URN @@ -214,7 +214,7 @@ func TestDescribeIG(t *testing.T) { channel := testChannelsIG[0] handler := newHandler("IG", "Instagram", false).(courier.URNDescriber) - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, nil) tcs := []struct { urn urns.URN @@ -233,7 +233,7 @@ func TestDescribeIG(t *testing.T) { func TestDescribeWAC(t *testing.T) { channel := testChannelsWAC[0] handler := newHandler("WAC", "Cloud API WhatsApp", false).(courier.URNDescriber) - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, nil) tcs := []struct { urn urns.URN diff --git a/handlers/http_test.go b/handlers/http_test.go index 6de7829c9..a10087b37 100644 --- a/handlers/http_test.go +++ b/handlers/http_test.go @@ -24,7 +24,7 @@ func TestDoHTTPRequest(t *testing.T) { mb := test.NewMockBackend() mc := test.NewMockChannel("7a8ff1d4-f211-4492-9d05-e1905f6da8c8", "NX", "1234", "EC", nil) mm := mb.NewOutgoingMsg(mc, courier.NewMsgID(123), urns.URN("tel:+1234"), "Hello World", false, nil, "", "") - clog := courier.NewChannelLogForSend(mm) + clog := courier.NewChannelLogForSend(mm, nil) req, _ := http.NewRequest("POST", "https://api.messages.com/send.json", nil) resp, respBody, err := handlers.RequestHTTP(req, clog) diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 82635c519..7348e1989 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -168,7 +168,7 @@ type fetchPayload struct { // fetchAccessToken tries to fetch a new token for our channel, setting the result in redis func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) error { - clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel, h.RedactValues(channel)) tokenURL, _ := url.Parse(fmt.Sprintf("%s/%s", sendURL, "auth/token.action")) payload := &fetchPayload{ diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index 522f47826..0eafdc563 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -272,7 +272,7 @@ func TestDescribeURN(t *testing.T) { s := newServer(mb) handler := &handler{handlers.NewBaseHandler(courier.ChannelType("JC"), "Jiochat")} handler.Initialize(s) - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], nil) tcs := []struct { urn urns.URN diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 4656032dc..4c044a189 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -360,7 +360,7 @@ func TestDescribeURN(t *testing.T) { defer server.Close() handler := newHandler().(courier.URNDescriber) - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], nil) urn, _ := urns.NewURNFromParts(urns.SlackScheme, "U012345", "", "") data := map[string]string{"name": "dummy user"} diff --git a/handlers/test.go b/handlers/test.go index bec3cbbcf..406cd58ac 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -246,7 +246,7 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour tc.SendPrep(server, handler, channel, msg) } - clog := courier.NewChannelLogForSend(msg) + clog := courier.NewChannelLogForSend(msg, nil) ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*10) status, err := handler.Send(ctx, msg, clog) diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index 9393c5350..88972637f 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -374,7 +374,7 @@ func TestDescribeURN(t *testing.T) { defer server.Close() handler := newHandler().(courier.URNDescriber) - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], nil) urn, _ := urns.NewURNFromParts(urns.VKScheme, "123456789", "", "") data := map[string]string{"name": "John Doe"} diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index 8e8af96c6..ad07bbb34 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -97,7 +97,7 @@ func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http // fetchAccessToken tries to fetch a new token for our channel, setting the result in redis func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) error { - clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel) + clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel, h.RedactValues(channel)) form := url.Values{ "grant_type": []string{"client_credential"}, diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index 7e6d992be..597f20c54 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -268,7 +268,7 @@ func TestDescribe(t *testing.T) { s := newServer(mb) handler := &handler{handlers.NewBaseHandler(courier.ChannelType("WC"), "WeChat")} handler.Initialize(s) - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], nil) tcs := []struct { urn urns.URN diff --git a/sender.go b/sender.go index 4cf2a1a96..e02c7ebd0 100644 --- a/sender.go +++ b/sender.go @@ -189,7 +189,7 @@ func (w *Sender) sendMessage(msg Msg) { } var status MsgStatus - clog := NewChannelLogForSend(msg) + clog := NewChannelLogForSend(msg, nil) // TODO get redact values from handler if sent { // if this message was already sent, create a wired status for it diff --git a/server.go b/server.go index 61e4fe503..475eccbfc 100644 --- a/server.go +++ b/server.go @@ -298,7 +298,7 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe } }() - clog := NewChannelLogForIncoming(recorder, channel) + clog := NewChannelLogForIncoming(channel, recorder, handler.RedactValues(channel)) events, hErr := handlerFunc(ctx, channel, recorder.ResponseWriter, r, clog) duration := time.Since(start) From d31ce63e6d6caa9db57b0e95d11d99fee916b6ed Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 25 Aug 2022 19:48:58 -0500 Subject: [PATCH 111/294] Fix local timezone dependent test --- backends/rapidpro/backend_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 4b25a170c..c1563cbae 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -1395,7 +1395,7 @@ func (ts *BackendTestSuite) TestResolveMedia() { } // check we've cached 3 media lookups - assertredis.HLen(ts.T(), ts.b.redisPool, fmt.Sprintf("media-lookups:%s", time.Now().Format("2006-01-02")), 3) + assertredis.HLen(ts.T(), ts.b.redisPool, fmt.Sprintf("media-lookups:%s", time.Now().In(time.UTC).Format("2006-01-02")), 3) } func TestMsgSuite(t *testing.T) { From 55e125576bc794bc83465bb6500f85543565a74e Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 26 Aug 2022 11:27:55 -0500 Subject: [PATCH 112/294] Update to last gocommon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1ac43f7e2..2b2eb7f52 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.6 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.28.2 + github.com/nyaruka/gocommon v1.29.0 github.com/nyaruka/null v1.2.0 github.com/nyaruka/redisx v0.2.2 github.com/patrickmn/go-cache v2.1.0+incompatible diff --git a/go.sum b/go.sum index b192d805d..401415384 100644 --- a/go.sum +++ b/go.sum @@ -76,8 +76,8 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.28.2 h1:1RoQWH2lJUszOL/fDgA72ktQ6z6vcz0PHKJJL73+s40= -github.com/nyaruka/gocommon v1.28.2/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= +github.com/nyaruka/gocommon v1.29.0 h1:BNhlqYiA0KceBgRmjWIOMSFsiEwtopkGGQ4W38wD56o= +github.com/nyaruka/gocommon v1.29.0/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= From 7b856aeff538521848808645807c60eb453dc96a Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 26 Aug 2022 11:38:59 -0500 Subject: [PATCH 113/294] Update CHANGELOG.md for v7.5.19 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5341df9e..a387de228 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +v7.5.19 +---------- + * Update to last gocommon + * Fix local timezone dependent test + * Don't fail CI for codecov problems + * Add UUID to channel logs + * Replace remaining usages of MakeHTTPRequest + v7.5.18 ---------- * Fix insert channel log SQL From 748ddede1efc8244b6ecefc9a0e2621d34945571 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 26 Aug 2022 15:20:40 -0500 Subject: [PATCH 114/294] Tidy clickmobile tests --- handlers/clickmobile/clickmobile_test.go | 144 +++++++++++++++++------ 1 file changed, 106 insertions(+), 38 deletions(-) diff --git a/handlers/clickmobile/clickmobile_test.go b/handlers/clickmobile/clickmobile_test.go index 21c76f0c4..cbcea2906 100644 --- a/handlers/clickmobile/clickmobile_test.go +++ b/handlers/clickmobile/clickmobile_test.go @@ -11,11 +11,9 @@ import ( "github.com/nyaruka/gocommon/dates" ) -var ( +const ( receiveURL = "/c/cm/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" - notXML = "empty" - validReceive = ` 2020 265990099333 @@ -67,21 +65,74 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+265990099333"), ExpectedExternalID: Sp("1232434354")}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURNReceive, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - - {Label: "Receive valid with empty text", URL: receiveURL, Data: validReceiveEmptyText, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+265990099333"), ExpectedExternalID: Sp("1232434354")}, - {Label: "Receive valid missing text", URL: receiveURL, Data: validMissingText, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+265990099333"), ExpectedExternalID: Sp("1232434354")}, - - {Label: "Receive valid missing referenceID", URL: receiveURL, Data: validMissingReferenceID, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+265990099333"), ExpectedExternalID: Sp("")}, - - {Label: "Missing Shortcode", URL: receiveURL, Data: missingShortcode, ExpectedStatus: 400, ExpectedResponse: "missing parameters, must have 'mobile' and 'shortcode'"}, - {Label: "Missing Mobile", URL: receiveURL, Data: missingMobile, ExpectedStatus: 400, ExpectedResponse: "missing parameters, must have 'mobile' and 'shortcode'"}, - {Label: "Receive invalid XML", URL: receiveURL, Data: notXML, ExpectedStatus: 400, ExpectedResponse: "unable to parse request XML"}, + { + Label: "Receive Valid Message", + URL: receiveURL, + Data: validReceive, + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: Sp("tel:+265990099333"), + ExpectedExternalID: Sp("1232434354"), + }, + { + Label: "Invalid URN", + URL: receiveURL, + Data: invalidURNReceive, + ExpectedStatus: 400, + ExpectedResponse: "phone number supplied is not a number", + }, + { + Label: "Receive valid with empty text", + URL: receiveURL, + Data: validReceiveEmptyText, + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedURN: Sp("tel:+265990099333"), + ExpectedExternalID: Sp("1232434354"), + }, + { + Label: "Receive valid missing text", + URL: receiveURL, + Data: validMissingText, + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedURN: Sp("tel:+265990099333"), + ExpectedExternalID: Sp("1232434354"), + }, + { + Label: "Receive valid missing referenceID", + URL: receiveURL, + Data: validMissingReferenceID, + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: Sp("tel:+265990099333"), + ExpectedExternalID: Sp(""), + }, + { + Label: "Missing Shortcode", + URL: receiveURL, + Data: missingShortcode, + ExpectedStatus: 400, + ExpectedResponse: "missing parameters, must have 'mobile' and 'shortcode'", + }, + { + Label: "Missing Mobile", + URL: receiveURL, + Data: missingMobile, + ExpectedStatus: 400, + ExpectedResponse: "missing parameters, must have 'mobile' and 'shortcode'", + }, + { + Label: "Receive invalid XML", + URL: receiveURL, + Data: "empty", + ExpectedStatus: 400, + ExpectedResponse: "unable to parse request XML", + }, } func TestHandler(t *testing.T) { @@ -100,34 +151,51 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: `{"code":"000","desc":"Operation successful.","data":{"new_record_id":"9"}}`, MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"code":"000","desc":"Operation successful.","data":{"new_record_id":"9"}}`, + MockResponseStatus: 200, ExpectedRequestBody: `{"app_id":"001-app","org_id":"001-org","user_id":"Username","timestamp":"20180411182430","auth_key":"3e1347ddb444d13aa23d11e097602be0","operation":"send","reference":"10","message_type":"1","src_address":"2020","dst_address":"+250788383383","message":"Simple Message"}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json"}, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: "☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: `{"code":"000","desc":"Operation successful.","data":{"new_record_id":"9"}}`, MockResponseStatus: 200, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"code":"000","desc":"Operation successful.","data":{"new_record_id":"9"}}`, + MockResponseStatus: 200, ExpectedRequestBody: `{"app_id":"001-app","org_id":"001-org","user_id":"Username","timestamp":"20180411182430","auth_key":"3e1347ddb444d13aa23d11e097602be0","operation":"send","reference":"10","message_type":"1","src_address":"2020","dst_address":"+250788383383","message":"☺"}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json"}, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `{"code":"001","desc":"Database SQL Error"}`, MockResponseStatus: 401, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"code":"001","desc":"Database SQL Error"}`, + MockResponseStatus: 401, ExpectedRequestBody: `{"app_id":"001-app","org_id":"001-org","user_id":"Username","timestamp":"20180411182430","auth_key":"3e1347ddb444d13aa23d11e097602be0","operation":"send","reference":"10","message_type":"1","src_address":"2020","dst_address":"+250788383383","message":"Error Message"}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json"}, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: `{"code":"000","desc":"Operation successful.","data":{"new_record_id":"9"}}`, MockResponseStatus: 200, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{"code":"000","desc":"Operation successful.","data":{"new_record_id":"9"}}`, + MockResponseStatus: 200, ExpectedRequestBody: `{"app_id":"001-app","org_id":"001-org","user_id":"Username","timestamp":"20180411182430","auth_key":"3e1347ddb444d13aa23d11e097602be0","operation":"send","reference":"10","message_type":"1","src_address":"2020","dst_address":"+250788383383","message":"My pic!\nhttps://foo.bar/image.jpg"}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json"}, - SendPrep: setSendURL}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { From 85475214b721e690cf83af9fb71da5b2093a14de Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 29 Aug 2022 09:31:03 -0500 Subject: [PATCH 115/294] Fix writing errors to channel logs --- backends/rapidpro/backend_test.go | 6 ++++-- backends/rapidpro/channel_log.go | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index c1563cbae..336e5d49a 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -3,6 +3,7 @@ package rapidpro import ( "context" "encoding/json" + "errors" "fmt" "io/ioutil" "log" @@ -974,6 +975,7 @@ func (ts *BackendTestSuite) TestWriteChanneLog() { clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel) clog.HTTP(trace) + clog.Error(errors.New("this is an error")) err = ts.b.WriteChannelLog(ctx, clog) ts.NoError(err) @@ -981,8 +983,8 @@ func (ts *BackendTestSuite) TestWriteChanneLog() { time.Sleep(time.Second) // give committer time to write this assertdb.Query(ts.T(), ts.b.db, `SELECT count(*) FROM channels_channellog`).Returns(1) - assertdb.Query(ts.T(), ts.b.db, `SELECT channel_id, http_logs->0->>'url' AS url FROM channels_channellog`). - Columns(map[string]interface{}{"channel_id": int64(channel.ID()), "url": "https://api.messages.com/send.json"}) + assertdb.Query(ts.T(), ts.b.db, `SELECT channel_id, http_logs->0->>'url' AS url, errors->0->>'message' AS err FROM channels_channellog`). + Columns(map[string]interface{}{"channel_id": int64(channel.ID()), "url": "https://api.messages.com/send.json", "err": "this is an error"}) } func (ts *BackendTestSuite) TestWriteAttachment() { diff --git a/backends/rapidpro/channel_log.go b/backends/rapidpro/channel_log.go index b6808de69..25e54d702 100644 --- a/backends/rapidpro/channel_log.go +++ b/backends/rapidpro/channel_log.go @@ -50,7 +50,7 @@ func queueChannelLog(ctx context.Context, b *backend, clog *courier.ChannelLog) } } - errors := make([]channelError, 0, len(clog.Errors())) + errors := make([]channelError, len(clog.Errors())) for i, e := range clog.Errors() { errors[i] = channelError{Message: e.Message(), Code: e.Code()} } From 705b73a2b501919fa7806809fd32e5493433bb5a Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 29 Aug 2022 09:53:07 -0500 Subject: [PATCH 116/294] Update CHANGELOG.md for v7.5.20 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a387de228..79bcbbdee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.20 +---------- + * Fix writing errors to channel logs + v7.5.19 ---------- * Update to last gocommon From 4d41b6e6b8cfb610553971509e3b4e942c7ef8cb Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 29 Aug 2022 12:18:34 -0500 Subject: [PATCH 117/294] Cleanup tests --- handlers/chikka/chikka_test.go | 91 ++- handlers/clicksend/clicksend_test.go | 24 +- handlers/dart/dart_test.go | 83 ++- handlers/discord/discord_test.go | 93 ++- handlers/dmark/dmark_test.go | 81 ++- handlers/external/external_test.go | 269 ++++++-- handlers/facebook/facebook_test.go | 278 ++++++-- handlers/facebookapp/facebookapp_test.go | 786 ++++++++++++++++++----- handlers/firebase/firebase_test.go | 57 +- handlers/freshchat/freshchat_test.go | 5 +- handlers/globe/globe_test.go | 113 +++- 11 files changed, 1477 insertions(+), 403 deletions(-) diff --git a/handlers/chikka/chikka_test.go b/handlers/chikka/chikka_test.go index 87e8bd95c..0fcfecca1 100644 --- a/handlers/chikka/chikka_test.go +++ b/handlers/chikka/chikka_test.go @@ -95,10 +95,12 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+63911231234", - ExpectedStatus: "W", - MockResponseBody: "Success", MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+63911231234", + MockResponseBody: "Success", + MockResponseStatus: 200, ExpectedPostParams: map[string]string{ "message": "Simple Message", "message_type": "SEND", @@ -109,12 +111,16 @@ var defaultSendTestCases = []ChannelSendTestCase{ "secret_key": "Password", "message_id": "10", }, - SendPrep: setSendURL}, - {Label: "Plain Reply", - MsgText: "Simple Message", MsgURN: "tel:+63911231234", - ExpectedStatus: "W", + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Plain Reply", + MsgText: "Simple Message", + MsgURN: "tel:+63911231234", MsgResponseToExternalID: "external-id", - MockResponseBody: "Success", MockResponseStatus: 200, + MockResponseBody: "Success", + MockResponseStatus: 200, ExpectedPostParams: map[string]string{ "message": "Simple Message", "message_type": "REPLY", @@ -126,9 +132,13 @@ var defaultSendTestCases = []ChannelSendTestCase{ "secret_key": "Password", "message_id": "10", }, - SendPrep: setSendURL}, - {Label: "Failed Reply use Send", - MsgText: "Simple Message", MsgURN: "tel:+63911231234", + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Failed Reply use Send", + MsgText: "Simple Message", + MsgURN: "tel:+63911231234", MsgResponseToExternalID: "external-id", MockResponseBody: `{"status":400,"message":"BAD REQUEST","description":"Invalid\\/Used Request ID"}`, MockResponseStatus: 400, @@ -142,11 +152,14 @@ var defaultSendTestCases = []ChannelSendTestCase{ "secret_key": "Password", "message_id": "10", }, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: "☺", MsgURN: "tel:+63911231234", - ExpectedStatus: "W", - MockResponseBody: "Success", MockResponseStatus: 200, + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "tel:+63911231234", + MockResponseBody: "Success", + MockResponseStatus: 200, ExpectedPostParams: map[string]string{ "message": "☺", "message_type": "SEND", @@ -157,12 +170,16 @@ var defaultSendTestCases = []ChannelSendTestCase{ "secret_key": "Password", "message_id": "10", }, - SendPrep: setSendURL}, - {Label: "Long Send", - MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - MsgURN: "tel:+63911231234", - ExpectedStatus: "W", - MockResponseBody: "Success", MockResponseStatus: 200, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Long Send", + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+63911231234", + ExpectedStatus: "W", + MockResponseBody: "Success", + MockResponseStatus: 200, ExpectedPostParams: map[string]string{ "message": "I need to keep adding more things to make it work", "message_type": "SEND", @@ -174,10 +191,13 @@ var defaultSendTestCases = []ChannelSendTestCase{ "message_id": "10", }, SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+63911231234", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: "Success", MockResponseStatus: 200, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+63911231234", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: "Success", + MockResponseStatus: 200, ExpectedPostParams: map[string]string{ "message": "My pic!\nhttps://foo.bar/image.jpg", "message_type": "SEND", @@ -188,11 +208,15 @@ var defaultSendTestCases = []ChannelSendTestCase{ "secret_key": "Password", "message_id": "10", }, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+63911231234", - ExpectedStatus: "E", - MockResponseBody: `ERROR`, MockResponseStatus: 401, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+63911231234", + MockResponseBody: `ERROR`, + MockResponseStatus: 401, ExpectedPostParams: map[string]string{ "message": "Error Message", "message_type": "SEND", @@ -203,7 +227,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ "secret_key": "Password", "message_id": "10", }, - SendPrep: setSendURL}, + ExpectedStatus: "E", + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/clicksend/clicksend_test.go b/handlers/clicksend/clicksend_test.go index a566e27ec..cf52719a7 100644 --- a/handlers/clicksend/clicksend_test.go +++ b/handlers/clicksend/clicksend_test.go @@ -9,7 +9,7 @@ import ( "github.com/nyaruka/courier/test" ) -var ( +const ( receiveURL = "/c/cs/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive" ) @@ -18,10 +18,24 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: `from=639171234567&body=hello+world`, Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+639171234567")}, - {Label: "Receive Missing From", URL: receiveURL, Data: `body=hello+world`, Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedStatus: 400, ExpectedResponse: "Error"}, + { + Label: "Receive Valid Message", + URL: receiveURL, + Data: `from=639171234567&body=hello+world`, + Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("hello world"), + ExpectedURN: Sp("tel:+639171234567"), + }, + { + Label: "Receive Missing From", + URL: receiveURL, + Data: `body=hello+world`, + Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + ExpectedStatus: 400, + ExpectedResponse: "Error", + }, } func TestHandler(t *testing.T) { diff --git a/handlers/dart/dart_test.go b/handlers/dart/dart_test.go index f83a49b66..41b4d9563 100644 --- a/handlers/dart/dart_test.go +++ b/handlers/dart/dart_test.go @@ -13,33 +13,74 @@ var daTestChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "DA", "2020", "ID", nil), } -var ( +const ( receiveURL = "/c/da/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" statusURL = "/c/da/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered/" - - validMessage = receiveURL + "?userid=testusr&password=test&original=6289881134560&sendto=2020&message=Msg" - invalidMessage = receiveURL - externalURN = receiveURL + "?userid=testusr&password=test&original=cmp-oodddqddwdwdcd&sendto=2020&message=Msg" - - validStatus = statusURL + "?status=10&messageid=12345" - validPartStatus = statusURL + "?status=10&messageid=12345.2" - failedStatus = statusURL + "?status=30&messageid=12345" - badStatus = statusURL + "?status=foo&messageid=12345" - badStatusMessageID = statusURL + "?status=10&messageid=abc" - missingStatus = statusURL + "?messageid=12345" ) var daTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: validMessage, ExpectedStatus: 200, ExpectedResponse: "000", ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+6289881134560")}, - {Label: "Receive Valid", URL: externalURN, ExpectedStatus: 200, ExpectedResponse: "000", ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("ext:cmp-oodddqddwdwdcd")}, - {Label: "Receive Invalid", URL: invalidMessage, ExpectedStatus: 400, ExpectedResponse: "missing required parameters original and sendto"}, + { + Label: "Receive Valid", + URL: receiveURL + "?userid=testusr&password=test&original=6289881134560&sendto=2020&message=Msg", + ExpectedStatus: 200, + ExpectedResponse: "000", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: Sp("tel:+6289881134560"), + }, + { + Label: "Receive Valid", + URL: receiveURL + "?userid=testusr&password=test&original=cmp-oodddqddwdwdcd&sendto=2020&message=Msg", + ExpectedStatus: 200, + ExpectedResponse: "000", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: Sp("ext:cmp-oodddqddwdwdcd"), + }, + { + Label: "Receive Invalid", + URL: receiveURL, + ExpectedStatus: 400, + ExpectedResponse: "missing required parameters original and sendto", + }, - {Label: "Valid Status", URL: validStatus, ExpectedStatus: 200, ExpectedResponse: "000", ExpectedMsgStatus: Sp("D")}, - {Label: "Valid Status", URL: validPartStatus, ExpectedStatus: 200, ExpectedResponse: "000", ExpectedMsgStatus: Sp("D")}, - {Label: "Failed Status", URL: failedStatus, ExpectedStatus: 200, ExpectedResponse: "000", ExpectedMsgStatus: Sp("F")}, - {Label: "Missing Status", URL: missingStatus, ExpectedStatus: 400, ExpectedResponse: "parameters messageid and status should not be empty"}, - {Label: "Missing Status", URL: badStatus, ExpectedStatus: 400, ExpectedResponse: "parsing failed: status 'foo' is not an integer"}, - {Label: "Missing Status", URL: badStatusMessageID, ExpectedStatus: 400, ExpectedResponse: "parsing failed: messageid 'abc' is not an integer"}, + { + Label: "Valid Status", + URL: statusURL + "?status=10&messageid=12345", + ExpectedStatus: 200, + ExpectedResponse: "000", + ExpectedMsgStatus: Sp("D"), + }, + { + Label: "Valid Status", + URL: statusURL + "?status=10&messageid=12345.2", + ExpectedStatus: 200, + ExpectedResponse: "000", + ExpectedMsgStatus: Sp("D"), + }, + { + Label: "Failed Status", + URL: statusURL + "?status=30&messageid=12345", + ExpectedStatus: 200, + ExpectedResponse: "000", + ExpectedMsgStatus: Sp("F"), + }, + { + Label: "Missing Status", + URL: statusURL + "?messageid=12345", + ExpectedStatus: 400, + ExpectedResponse: "parameters messageid and status should not be empty", + }, + { + Label: "Missing Status", + URL: statusURL + "?status=foo&messageid=12345", + ExpectedStatus: 400, + ExpectedResponse: "parsing failed: status 'foo' is not an integer", + }, + { + Label: "Missing Status", + URL: statusURL + "?status=10&messageid=abc", + ExpectedStatus: 400, + ExpectedResponse: "parsing failed: messageid 'abc' is not an integer", + }, } func TestHandler(t *testing.T) { diff --git a/handlers/discord/discord_test.go b/handlers/discord/discord_test.go index 9770b8a58..e38289328 100644 --- a/handlers/discord/discord_test.go +++ b/handlers/discord/discord_test.go @@ -23,19 +23,90 @@ var testChannels = []courier.Channel{ } var testCases = []ChannelHandleTestCase{ - {Label: "Recieve Message", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", Data: `from=694634743521607802&text=hello`, ExpectedStatus: 200, ExpectedMsgText: Sp("hello"), ExpectedURN: Sp("discord:694634743521607802")}, - {Label: "Recieve Message with attachment", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", Data: `from=694634743521607802&text=hello&attachments=https://test.test/foo.png`, ExpectedStatus: 200, ExpectedMsgText: Sp("hello"), ExpectedURN: Sp("discord:694634743521607802"), ExpectedAttachments: []string{"https://test.test/foo.png"}}, - {Label: "Invalid ID", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", Data: `from=somebody&text=hello`, ExpectedStatus: 400, ExpectedResponse: "Error"}, - {Label: "Garbage Body", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", Data: `sdfaskdfajsdkfajsdfaksdf`, ExpectedStatus: 400, ExpectedResponse: "Error"}, - {Label: "Missing Text", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", Data: `from=694634743521607802`, ExpectedStatus: 400, ExpectedResponse: "Error"}, - {Label: "Message Sent Handler", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/sent/", Data: `id=12345`, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, - {Label: "Message Sent Handler Garbage", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/sent/", Data: `nothing`, ExpectedStatus: 400}, + { + Label: "Recieve Message", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", + Data: `from=694634743521607802&text=hello`, + ExpectedStatus: 200, + ExpectedMsgText: Sp("hello"), + ExpectedURN: Sp("discord:694634743521607802"), + }, + { + Label: "Recieve Message with attachment", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", + Data: `from=694634743521607802&text=hello&attachments=https://test.test/foo.png`, + ExpectedStatus: 200, + ExpectedMsgText: Sp("hello"), + ExpectedURN: Sp("discord:694634743521607802"), + ExpectedAttachments: []string{"https://test.test/foo.png"}, + }, + { + Label: "Invalid ID", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", + Data: `from=somebody&text=hello`, + ExpectedStatus: 400, + ExpectedResponse: "Error", + }, + { + Label: "Garbage Body", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", + Data: `sdfaskdfajsdkfajsdfaksdf`, + ExpectedStatus: 400, + ExpectedResponse: "Error", + }, + { + Label: "Missing Text", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", + Data: `from=694634743521607802`, + ExpectedStatus: 400, + ExpectedResponse: "Error", + }, + { + Label: "Message Sent Handler", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/sent/", + Data: `id=12345`, + ExpectedStatus: 200, + ExpectedResponse: `"status":"S"`, + }, + { + Label: "Message Sent Handler Garbage", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/sent/", + Data: `nothing`, + ExpectedStatus: 400, + }, } var sendTestCases = []ChannelSendTestCase{ - {Label: "Simple Send", MsgText: "Hello World", MsgURN: "discord:694634743521607802", ExpectedRequestPath: "/discord/rp/send", MockResponseStatus: 200, ExpectedRequestBody: `{"id":"10","text":"Hello World","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":[],"quick_replies":null}`, SendPrep: setSendURL}, - {Label: "Simple Send", MsgText: "Hello World", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MsgURN: "discord:694634743521607802", ExpectedRequestPath: "/discord/rp/send", ExpectedRequestBody: `{"id":"10","text":"Hello World","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":["https://foo.bar/image.jpg"],"quick_replies":null}`, MockResponseStatus: 200, SendPrep: setSendURL}, - {Label: "Simple Send with attachements and Quick Replies", MsgText: "Hello World", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MsgQuickReplies: []string{"hello", "world"}, MsgURN: "discord:694634743521607802", ExpectedRequestPath: "/discord/rp/send", ExpectedRequestBody: `{"id":"10","text":"Hello World","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":["https://foo.bar/image.jpg"],"quick_replies":["hello","world"]}`, MockResponseStatus: 200, SendPrep: setSendURL}, + { + Label: "Simple Send", + MsgText: "Hello World", + MsgURN: "discord:694634743521607802", + ExpectedRequestPath: "/discord/rp/send", + MockResponseStatus: 200, + ExpectedRequestBody: `{"id":"10","text":"Hello World","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":[],"quick_replies":null}`, + SendPrep: setSendURL, + }, + { + Label: "Simple Send", + MsgText: "Hello World", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MsgURN: "discord:694634743521607802", + ExpectedRequestPath: "/discord/rp/send", + ExpectedRequestBody: `{"id":"10","text":"Hello World","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":["https://foo.bar/image.jpg"],"quick_replies":null}`, + MockResponseStatus: 200, + SendPrep: setSendURL, + }, + { + Label: "Simple Send with attachements and Quick Replies", + MsgText: "Hello World", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MsgQuickReplies: []string{"hello", "world"}, + MsgURN: "discord:694634743521607802", + ExpectedRequestPath: "/discord/rp/send", + ExpectedRequestBody: `{"id":"10","text":"Hello World","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":["https://foo.bar/image.jpg"],"quick_replies":["hello","world"]}`, + MockResponseStatus: 200, + SendPrep: setSendURL, + }, } // setSendURL takes care of setting the send_url to our test server host @@ -45,7 +116,7 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, sendURL, _ = utils.AddURLPath(s.URL, sendURL) c.(*test.MockChannel).SetConfig(courier.ConfigSendURL, sendURL) } -func TestSending(t *testing.T) { +func TestSending(t *testing.T) { RunChannelSendTestCases(t, testChannels[0], newHandler(), sendTestCases, nil) } diff --git a/handlers/dmark/dmark_test.go b/handlers/dmark/dmark_test.go index 23affbf45..f6e714d61 100644 --- a/handlers/dmark/dmark_test.go +++ b/handlers/dmark/dmark_test.go @@ -14,34 +14,71 @@ var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "DM", "2020", "RW", nil), } -var ( +const ( receiveURL = "/c/dk/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" statusURL = "/c/dk/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/" - - emptyReceive = "empty" - validReceive = "text=Msg&short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=254791541111" - invalidURN = "text=Msg&short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=MTN" - missingText = "short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=254791541111" - invalidTS = "text=Msg&short_code=2020&tstamp=2017-10-26&msisdn=254791541111" - - missingStatus = "id=12345" - invalidStatus = "id=12345&status=Borked" - validStatus = "id=12345&status=1" ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111"), - ExpectedDate: time.Date(2017, 10, 26, 15, 51, 32, 906335000, time.UTC), + { + Label: "Receive Valid", + URL: receiveURL, + Data: "text=Msg&short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=254791541111", + ExpectedStatus: 200, + ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: Sp("tel:+254791541111"), + ExpectedDate: time.Date(2017, 10, 26, 15, 51, 32, 906335000, time.UTC), + }, + { + Label: "Invalid URN", + URL: receiveURL, + Data: "text=Msg&short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=MTN", + ExpectedStatus: 400, + ExpectedResponse: "phone number supplied is not a number", + }, + { + Label: "Receive Empty", + URL: receiveURL, + Data: "empty", + ExpectedStatus: 400, + ExpectedResponse: "field 'msisdn' required", + }, + { + Label: "Receive Missing Text", + URL: receiveURL, + Data: "short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=254791541111", + ExpectedStatus: 400, + ExpectedResponse: "field 'text' required", + }, + { + Label: "Receive Invalid TS", + URL: receiveURL, + Data: "text=Msg&short_code=2020&tstamp=2017-10-26&msisdn=254791541111", + ExpectedStatus: 400, + ExpectedResponse: "invalid tstamp", + }, + { + Label: "Status Invalid", + URL: statusURL, + ExpectedStatus: 400, + Data: "id=12345&status=Borked", + ExpectedResponse: "unknown status", + }, + { + Label: "Status Missing", + URL: statusURL, + ExpectedStatus: 400, + Data: "id=12345", + ExpectedResponse: "field 'status' required", + }, + { + Label: "Status Valid", + URL: statusURL, + ExpectedStatus: 200, + Data: "id=12345&status=1", + ExpectedResponse: `"status":"D"`, }, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Receive Empty", URL: receiveURL, Data: emptyReceive, ExpectedStatus: 400, ExpectedResponse: "field 'msisdn' required"}, - {Label: "Receive Missing Text", URL: receiveURL, Data: missingText, ExpectedStatus: 400, ExpectedResponse: "field 'text' required"}, - {Label: "Receive Invalid TS", URL: receiveURL, Data: invalidTS, ExpectedStatus: 400, ExpectedResponse: "invalid tstamp"}, - - {Label: "Status Invalid", URL: statusURL, ExpectedStatus: 400, Data: invalidStatus, ExpectedResponse: "unknown status"}, - {Label: "Status Missing", URL: statusURL, ExpectedStatus: 400, Data: missingStatus, ExpectedResponse: "field 'status' required"}, - {Label: "Status Valid", URL: statusURL, ExpectedStatus: 200, Data: validStatus, ExpectedResponse: `"status":"D"`}, } func TestHandler(t *testing.T) { diff --git a/handlers/external/external_test.go b/handlers/external/external_test.go index e1b8d3b83..72f0c6094 100644 --- a/handlers/external/external_test.go +++ b/handlers/external/external_test.go @@ -1,37 +1,19 @@ package external import ( + "net/http" "net/http/httptest" "testing" "time" - "net/http" - "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" "github.com/nyaruka/courier/utils" ) -var ( - receiveValidMessage = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sender=%2B2349067554729&text=Join" - receiveValidMessageFrom = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?from=%2B2349067554729&text=Join" - receiveValidNoPlus = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?from=2349067554729&text=Join" - receiveValidMessageWithDate = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sender=%2B2349067554729&text=Join&date=2017-06-23T12:30:00.500Z" - receiveValidMessageWithTime = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sender=%2B2349067554729&text=Join&time=2017-06-23T12:30:00Z" - receiveNoParams = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" - invalidURN = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sender=MTN&text=Join" - receiveNoSender = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?text=Join" - receiveInvalidDate = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sender=%2B2349067554729&text=Join&time=20170623T123000Z" - failedNoParams = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/failed/" - failedValid = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/failed/?id=12345" - sentValid = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/sent/?id=12345" - invalidStatus = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/wired/" - deliveredValid = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered/?id=12345" - deliveredValidPost = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered/" - stoppedEvent = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/?from=%2B2349067554729" - stoppedEventPost = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/" - stoppedEventInvalidURN = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/?from=MTN" +const ( + receiveURL = "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" ) var testChannels = []courier.Channel{ @@ -43,35 +25,162 @@ var gmChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, - {Label: "Receive Valid Post", URL: receiveNoParams, Data: "sender=%2B2349067554729&text=Join", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, - - {Label: "Receive Valid Post multipart form", URL: receiveNoParams, MultipartFormFields: map[string]string{"sender": "2349067554729", "text": "Join"}, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, - {Label: "Receive Valid From", URL: receiveValidMessageFrom, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, - {Label: "Receive Country Parse", URL: receiveValidNoPlus, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, - {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC)}, - {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC)}, - {Label: "Invalid URN", URL: invalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from' set"}, - {Label: "Receive No Sender", URL: receiveNoSender, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from' set"}, - {Label: "Receive Invalid Date", URL: receiveInvalidDate, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "invalid date format, must be RFC 3339"}, - {Label: "Failed No Params", URL: failedNoParams, ExpectedStatus: 400, ExpectedResponse: "field 'id' required"}, - {Label: "Failed Valid", URL: failedValid, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`}, - {Label: "Invalid Status", URL: invalidStatus, ExpectedStatus: 404, ExpectedResponse: `page not found`}, - {Label: "Sent Valid", URL: sentValid, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, - {Label: "Delivered Valid", URL: deliveredValid, ExpectedStatus: 200, Data: "nothing", ExpectedResponse: `"status":"D"`}, - {Label: "Delivered Valid Post", URL: deliveredValidPost, Data: "id=12345", ExpectedStatus: 200, ExpectedResponse: `"status":"D"`}, - {Label: "Stopped Event", URL: stoppedEvent, ExpectedStatus: 200, Data: "nothing", ExpectedResponse: "Accepted"}, - {Label: "Stopped Event Post", URL: stoppedEventPost, Data: "from=%2B2349067554729", ExpectedStatus: 200, ExpectedResponse: "Accepted"}, - {Label: "Stopped Event Invalid URN", URL: stoppedEventInvalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Stopped event No Params", URL: stoppedEventPost, ExpectedStatus: 400, ExpectedResponse: "field 'from' required"}, + { + Label: "Receive Valid Message", + URL: receiveURL + "?sender=%2B2349067554729&text=Join", + Data: "empty", + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: Sp("tel:+2349067554729"), + }, + { + Label: "Receive Valid Post", + URL: receiveURL, + Data: "sender=%2B2349067554729&text=Join", + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: Sp("tel:+2349067554729"), + }, + { + Label: "Receive Valid Post multipart form", + URL: receiveURL, + MultipartFormFields: map[string]string{"sender": "2349067554729", "text": "Join"}, + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: Sp("tel:+2349067554729"), + }, + { + Label: "Receive Valid From", + URL: receiveURL + "?from=%2B2349067554729&text=Join", + Data: "empty", + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: Sp("tel:+2349067554729"), + }, + { + Label: "Receive Country Parse", + URL: receiveURL + "?from=2349067554729&text=Join", + Data: "empty", + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: Sp("tel:+2349067554729"), + }, + { + Label: "Receive Valid Message With Date", + URL: receiveURL + "?sender=%2B2349067554729&text=Join&date=2017-06-23T12:30:00.500Z", + Data: "empty", + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: Sp("tel:+2349067554729"), + ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC), + }, + { + Label: "Receive Valid Message With Time", + URL: receiveURL + "?sender=%2B2349067554729&text=Join&time=2017-06-23T12:30:00Z", + Data: "empty", + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: Sp("tel:+2349067554729"), + ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC), + }, + { + Label: "Invalid URN", + URL: receiveURL + "?sender=MTN&text=Join", + Data: "empty", + ExpectedStatus: 400, + ExpectedResponse: "phone number supplied is not a number", + }, + { + Label: "Receive No Params", + URL: receiveURL, + Data: "empty", + ExpectedStatus: 400, + ExpectedResponse: "must have one of 'sender' or 'from' set", + }, + { + Label: "Receive No Sender", + URL: receiveURL + "?text=Join", + Data: "empty", + ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from' set", + }, + { + Label: "Receive Invalid Date", + URL: receiveURL + "?sender=%2B2349067554729&text=Join&time=20170623T123000Z", + Data: "empty", + ExpectedStatus: 400, + ExpectedResponse: "invalid date format, must be RFC 3339", + }, + { + Label: "Failed No Params", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/failed/", + ExpectedStatus: 400, + ExpectedResponse: "field 'id' required", + }, + { + Label: "Failed Valid", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/failed/?id=12345", + ExpectedStatus: 200, + ExpectedResponse: `"status":"F"`, + }, + { + Label: "Invalid Status", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/wired/", + ExpectedStatus: 404, + ExpectedResponse: `page not found`, + }, + { + Label: "Sent Valid", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/sent/?id=12345", + ExpectedStatus: 200, + ExpectedResponse: `"status":"S"`}, + { + Label: "Delivered Valid", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered/?id=12345", + ExpectedStatus: 200, + Data: "nothing", + ExpectedResponse: `"status":"D"`, + }, + { + Label: "Delivered Valid Post", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered/", + Data: "id=12345", + ExpectedStatus: 200, + ExpectedResponse: `"status":"D"`, + }, + { + Label: "Stopped Event", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/?from=%2B2349067554729", + ExpectedStatus: 200, + Data: "nothing", + ExpectedResponse: "Accepted", + }, + { + Label: "Stopped Event Post", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/", + Data: "from=%2B2349067554729", + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + }, + { + Label: "Stopped Event Invalid URN", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/?from=MTN", + Data: "empty", + ExpectedStatus: 400, + ExpectedResponse: "phone number supplied is not a number", + }, + { + Label: "Stopped event No Params", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/", + ExpectedStatus: 400, + ExpectedResponse: "field 'from' required", + }, } var testSOAPReceiveChannels = []courier.Channel{ @@ -81,19 +190,39 @@ var testSOAPReceiveChannels = []courier.Channel{ configFromXPath: "//source", configMOResponse: "0", configMOResponseContentType: "text/xml", - })} + }, + ), +} var handleSOAPReceiveTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Post SOAP", URL: receiveNoParams, Data: `2349067554729Join`, - ExpectedStatus: 200, ExpectedResponse: "0", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, - {Label: "Receive Invalid SOAP", URL: receiveNoParams, Data: ``, - ExpectedStatus: 400, ExpectedResponse: "missing from"}, + { + Label: "Receive Valid Post SOAP", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + Data: `2349067554729Join`, + ExpectedStatus: 200, + ExpectedResponse: "0", + ExpectedMsgText: Sp("Join"), + ExpectedURN: Sp("tel:+2349067554729"), + }, + { + Label: "Receive Invalid SOAP", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + Data: ``, + ExpectedStatus: 400, + ExpectedResponse: "missing from", + }, } var gmTestCases = []ChannelHandleTestCase{ - {Label: "Receive Non Plus Message", URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sender=2207222333&text=Join", Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2207222333")}, + { + Label: "Receive Non Plus Message", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sender=2207222333&text=Join", + Data: "empty", + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: Sp("tel:+2207222333"), + }, } var customChannels = []courier.Channel{ @@ -102,12 +231,28 @@ var customChannels = []courier.Channel{ configMOFromField: "from_number", configMODateField: "timestamp", configMOTextField: "messageText", - })} + }, + ), +} var customTestCases = []ChannelHandleTestCase{ - {Label: "Receive Custom Message", URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?from_number=12067799192&messageText=Join×tamp=2017-06-23T12:30:00Z", Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+12067799192"), ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC)}, - {Label: "Receive Custom Missing", URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sent_from=12067799192&messageText=Join", Data: "empty", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from' set"}, + { + Label: "Receive Custom Message", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?from_number=12067799192&messageText=Join×tamp=2017-06-23T12:30:00Z", + Data: "empty", + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: Sp("tel:+12067799192"), + ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC), + }, + { + Label: "Receive Custom Missing", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sent_from=12067799192&messageText=Join", + Data: "empty", + ExpectedStatus: 400, + ExpectedResponse: "must have one of 'sender' or 'from' set", + }, } func TestHandler(t *testing.T) { diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index cc9ed5c28..f1abc4191 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -9,12 +9,11 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" - "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/urns" + "github.com/stretchr/testify/assert" ) var testChannels = []courier.Channel{ @@ -22,6 +21,10 @@ var testChannels = []courier.Channel{ map[string]interface{}{courier.ConfigAuthToken: "a123", courier.ConfigSecret: "mysecret"}), } +const ( + receiveURL = "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive" +) + var helloMsg = `{ "object":"page", "entry": [{ @@ -414,54 +417,196 @@ var unkownMessagingEntry = `{ }] }` -var notJSON = `blargh` - var testCases = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)}, - {Label: "No Duplicate Receive Message", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: duplicateMsg, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)}, - {Label: "Receive Attachment", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: attachment, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)}, - - {Label: "Receive Location", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: locationAttachment, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)}, - - {Label: "Receive Thumbs Up", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: thumbsUp, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp("👍"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)}, - - {Label: "Receive OptIn UserRef", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: optInUserRef, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:ref:optin_user_ref"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}}, - {Label: "Receive OptIn", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: optIn, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}}, - - {Label: "Receive Get Started", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: postbackGetStarted, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.NewConversation, - ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}}, - {Label: "Receive Referral Postback", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: postback, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, - ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}}, - {Label: "Receive Referral", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: postbackReferral, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, - ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}}, - - {Label: "Receive Referral", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: referral, ExpectedStatus: 200, ExpectedResponse: `"referrer_id":"referral id"`, - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, - ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}}, - - {Label: "Receive DLR", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: dlr, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedMsgStatus: Sp(courier.MsgDelivered), ExpectedExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233")}, - - {Label: "Different Page", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: differentPage, ExpectedStatus: 200, ExpectedResponse: `"data":[]`}, - {Label: "Echo", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: echo, ExpectedStatus: 200, ExpectedResponse: `ignoring echo`}, - {Label: "Not Page", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: notPage, ExpectedStatus: 200, ExpectedResponse: "ignoring"}, - {Label: "No Entries", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: noEntries, ExpectedStatus: 200, ExpectedResponse: "ignoring"}, - {Label: "No Messaging Entries", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: noMessagingEntries, ExpectedStatus: 200, ExpectedResponse: "Handled"}, - {Label: "Unknown Messaging Entry", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: unkownMessagingEntry, ExpectedStatus: 200, ExpectedResponse: "Handled"}, - {Label: "Not JSON", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "Error"}, - {Label: "Invalid URN", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "invalid facebook id"}, + { + Label: "Receive Message", + URL: receiveURL, + Data: helloMsg, + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: Sp("facebook:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + }, + { + Label: "No Duplicate Receive Message", + URL: receiveURL, + Data: duplicateMsg, + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: Sp("facebook:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + }, + { + Label: "Receive Attachment", + URL: receiveURL, + Data: attachment, + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"https://image-url/foo.png"}, + ExpectedURN: Sp("facebook:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + }, + { + Label: "Receive Location", + URL: receiveURL, + Data: locationAttachment, + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, + ExpectedURN: Sp("facebook:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + }, + { + Label: "Receive Thumbs Up", + URL: receiveURL, + Data: thumbsUp, + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedMsgText: Sp("👍"), + ExpectedURN: Sp("facebook:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + }, + { + Label: "Receive OptIn UserRef", + URL: receiveURL, + Data: optInUserRef, + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:ref:optin_user_ref"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedChannelEvent: courier.Referral, + ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, + }, + { + Label: "Receive OptIn", + URL: receiveURL, + Data: optIn, + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:5678"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedChannelEvent: courier.Referral, + ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, + }, + { + Label: "Receive Get Started", + URL: receiveURL, + Data: postbackGetStarted, + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:5678"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedChannelEvent: courier.NewConversation, + ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, + }, + { + Label: "Receive Referral Postback", + URL: receiveURL, + Data: postback, + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:5678"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedChannelEvent: courier.Referral, + ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, + }, + { + Label: "Receive Referral", + URL: receiveURL, + Data: postbackReferral, + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:5678"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedChannelEvent: courier.Referral, + ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, + }, + { + Label: "Receive Referral", + URL: receiveURL, + Data: referral, + ExpectedStatus: 200, + ExpectedResponse: `"referrer_id":"referral id"`, + ExpectedURN: Sp("facebook:5678"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedChannelEvent: courier.Referral, + ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, + }, + { + Label: "Receive DLR", + URL: receiveURL, + Data: dlr, + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedMsgStatus: Sp(courier.MsgDelivered), + ExpectedExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233"), + }, + { + Label: "Different Page", + URL: receiveURL, + Data: differentPage, + ExpectedStatus: 200, + ExpectedResponse: `"data":[]`, + }, + { + Label: "Echo", + URL: receiveURL, + Data: echo, + ExpectedStatus: 200, + ExpectedResponse: `ignoring echo`, + }, + { + Label: "Not Page", + URL: receiveURL, + Data: notPage, + ExpectedStatus: 200, + ExpectedResponse: "ignoring", + }, + { + Label: "No Entries", + URL: receiveURL, + Data: noEntries, + ExpectedStatus: 200, + ExpectedResponse: "ignoring", + }, + { + Label: "No Messaging Entries", + URL: receiveURL, + Data: noMessagingEntries, + ExpectedStatus: 200, + ExpectedResponse: "Handled", + }, + { + Label: "Unknown Messaging Entry", + URL: receiveURL, + Data: unkownMessagingEntry, + ExpectedStatus: 200, + ExpectedResponse: "Handled", + }, + { + Label: "Not JSON", + URL: receiveURL, + Data: `blargh`, + ExpectedStatus: 400, + ExpectedResponse: "Error", + }, + { + Label: "Invalid URN", + URL: receiveURL, + Data: invalidURN, + ExpectedStatus: 400, + ExpectedResponse: "invalid facebook id", + }, } // mocks the call to the Facebook graph API @@ -546,11 +691,36 @@ func TestVerify(t *testing.T) { subscribeTimeout = time.Millisecond RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ - {Label: "Receive Message", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: helloMsg, ExpectedStatus: 200}, - {Label: "Verify No Mode", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", ExpectedStatus: 400, ExpectedResponse: "unknown request"}, - {Label: "Verify No Secret", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe", ExpectedStatus: 400, ExpectedResponse: "token does not match secret"}, - {Label: "Invalid Secret", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe&hub.verify_token=blah", ExpectedStatus: 400, ExpectedResponse: "token does not match secret"}, - {Label: "Valid Secret", URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe&hub.verify_token=mysecret&hub.challenge=yarchallenge", ExpectedStatus: 200, ExpectedResponse: "yarchallenge"}, + { + Label: "Receive Message", + URL: receiveURL, + Data: helloMsg, + ExpectedStatus: 200, + }, + { + Label: "Verify No Mode", + URL: receiveURL, + ExpectedStatus: 400, + ExpectedResponse: "unknown request", + }, + { + Label: "Verify No Secret", + URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe", + ExpectedStatus: 400, + ExpectedResponse: "token does not match secret", + }, + { + Label: "Invalid Secret", + URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe&hub.verify_token=blah", + ExpectedStatus: 400, + ExpectedResponse: "token does not match secret", + }, + { + Label: "Valid Secret", + URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe&hub.verify_token=mysecret&hub.challenge=yarchallenge", + ExpectedStatus: 200, + ExpectedResponse: "yarchallenge", + }, }) // wait for our subscribe to be called diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 2657f0a30..31a514dae 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -11,7 +11,6 @@ import ( "time" "github.com/nyaruka/courier" - "github.com/nyaruka/courier/handlers" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/httpx" @@ -32,102 +31,383 @@ var testChannelsWAC = []courier.Channel{ } var testCasesFBA = []ChannelHandleTestCase{ - {Label: "Receive Message FBA", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature}, - {Label: "Receive Invalid Signature", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), ExpectedStatus: 400, ExpectedResponse: "invalid request signature", PrepRequest: addInvalidSignature}, - - {Label: "No Duplicate Receive Message", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/duplicateMsgFBA.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature}, - {Label: "Receive Attachment", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/attachmentFBA.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature}, - - {Label: "Receive Location", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/locationAttachment.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature}, - {Label: "Receive Thumbs Up", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/thumbsUp.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp("👍"), ExpectedURN: Sp("facebook:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature}, - - {Label: "Receive OptIn UserRef", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/optInUserRef.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:ref:optin_user_ref"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, - PrepRequest: addValidSignature}, - {Label: "Receive OptIn", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/optIn.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, - PrepRequest: addValidSignature}, - - {Label: "Receive Get Started", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postbackGetStarted.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.NewConversation, + { + Label: "Receive Message FBA", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + NoQueueErrorCheck: true, + NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: Sp("facebook:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Invalid Signature", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), + ExpectedStatus: 400, + ExpectedResponse: "invalid request signature", + PrepRequest: addInvalidSignature, + }, + { + Label: "No Duplicate Receive Message", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/duplicateMsgFBA.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: Sp("facebook:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Attachment", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/attachmentFBA.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"https://image-url/foo.png"}, + ExpectedURN: Sp("facebook:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Location", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/locationAttachment.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, + ExpectedURN: Sp("facebook:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Thumbs Up", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/thumbsUp.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedMsgText: Sp("👍"), + ExpectedURN: Sp("facebook:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive OptIn UserRef", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/optInUserRef.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:ref:optin_user_ref"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedChannelEvent: courier.Referral, + ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, + PrepRequest: addValidSignature, + }, + { + Label: "Receive OptIn", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/optIn.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:5678"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedChannelEvent: courier.Referral, + ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, + PrepRequest: addValidSignature, + }, + { + Label: "Receive Get Started", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/postbackGetStarted.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:5678"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedChannelEvent: courier.NewConversation, ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, - PrepRequest: addValidSignature}, - {Label: "Receive Referral Postback", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postback.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, + PrepRequest: addValidSignature, + }, + { + Label: "Receive Referral Postback", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/postback.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:5678"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, - PrepRequest: addValidSignature}, - {Label: "Receive Referral", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/postbackReferral.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, + PrepRequest: addValidSignature, + }, + { + Label: "Receive Referral", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/postbackReferral.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedURN: Sp("facebook:5678"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, - PrepRequest: addValidSignature}, - - {Label: "Receive Referral", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/referral.json")), ExpectedStatus: 200, ExpectedResponse: `"referrer_id":"referral id"`, - ExpectedURN: Sp("facebook:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, + PrepRequest: addValidSignature, + }, + { + Label: "Receive Referral", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/referral.json")), + ExpectedStatus: 200, + ExpectedResponse: `"referrer_id":"referral id"`, + ExpectedURN: Sp("facebook:5678"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, - PrepRequest: addValidSignature}, - - {Label: "Receive DLR", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/dlr.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedMsgStatus: Sp(courier.MsgDelivered), ExpectedExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233"), - PrepRequest: addValidSignature}, - - {Label: "Different Page", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/differentPageFBA.json")), ExpectedStatus: 200, ExpectedResponse: `"data":[]`, PrepRequest: addValidSignature}, - {Label: "Echo", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/echoFBA.json")), ExpectedStatus: 200, ExpectedResponse: `ignoring echo`, PrepRequest: addValidSignature}, - {Label: "Not Page", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/notPage.json")), ExpectedStatus: 400, ExpectedResponse: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notpage", PrepRequest: addValidSignature}, - {Label: "No Entries", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/noEntriesFBA.json")), ExpectedStatus: 400, ExpectedResponse: "no entries found", PrepRequest: addValidSignature}, - {Label: "No Messaging Entries", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/noMessagingEntriesFBA.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", PrepRequest: addValidSignature}, - {Label: "Unknown Messaging Entry", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/unknownMessagingEntryFBA.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", PrepRequest: addValidSignature}, - {Label: "Not JSON", URL: "/c/fba/receive", Data: "not JSON", ExpectedStatus: 400, ExpectedResponse: "Error", PrepRequest: addValidSignature}, - {Label: "Invalid URN", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/invalidURNFBA.json")), ExpectedStatus: 400, ExpectedResponse: "invalid facebook id", PrepRequest: addValidSignature}, + PrepRequest: addValidSignature, + }, + { + Label: "Receive DLR", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/dlr.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedMsgStatus: Sp(courier.MsgDelivered), + ExpectedExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233"), + PrepRequest: addValidSignature, + }, + { + Label: "Different Page", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/differentPageFBA.json")), + ExpectedStatus: 200, + ExpectedResponse: `"data":[]`, + PrepRequest: addValidSignature, + }, + { + Label: "Echo", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/echoFBA.json")), + ExpectedStatus: 200, + ExpectedResponse: `ignoring echo`, + PrepRequest: addValidSignature, + }, + { + Label: "Not Page", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/notPage.json")), + ExpectedStatus: 400, + ExpectedResponse: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notpage", + PrepRequest: addValidSignature, + }, + { + Label: "No Entries", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/noEntriesFBA.json")), + ExpectedStatus: 400, + ExpectedResponse: "no entries found", + PrepRequest: addValidSignature, + }, + { + Label: "No Messaging Entries", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/noMessagingEntriesFBA.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + PrepRequest: addValidSignature, + }, + { + Label: "Unknown Messaging Entry", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/unknownMessagingEntryFBA.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + PrepRequest: addValidSignature, + }, + { + Label: "Not JSON", + URL: "/c/fba/receive", + Data: "not JSON", + ExpectedStatus: 400, + ExpectedResponse: "Error", + PrepRequest: addValidSignature, + }, + { + Label: "Invalid URN", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/invalidURNFBA.json")), + ExpectedStatus: 400, + ExpectedResponse: "invalid facebook id", + PrepRequest: addValidSignature, + }, } -var testCasesIG = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("instagram:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature}, - {Label: "Receive Invalid Signature", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), ExpectedStatus: 400, ExpectedResponse: "invalid request signature", PrepRequest: addInvalidSignature}, - - {Label: "No Duplicate Receive Message", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/duplicateMsgIG.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("instagram:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature}, - - {Label: "Receive Attachment", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/attachmentIG.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, ExpectedURN: Sp("instagram:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature}, - - {Label: "Receive Like Heart", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/like_heart.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedMsgText: Sp(""), ExpectedURN: Sp("instagram:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature}, - - {Label: "Receive Icebreaker Get Started", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/icebreakerGetStarted.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("instagram:5678"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.NewConversation, +var testCasesIG = []ChannelHandleTestCase{ + { + Label: "Receive Message", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + NoQueueErrorCheck: true, + NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: Sp("instagram:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Invalid Signature", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), + ExpectedStatus: 400, + ExpectedResponse: "invalid request signature", + PrepRequest: addInvalidSignature, + }, + { + Label: "No Duplicate Receive Message", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/duplicateMsgIG.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: Sp("instagram:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Attachment", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/attachmentIG.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"https://image-url/foo.png"}, + ExpectedURN: Sp("instagram:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Like Heart", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/like_heart.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedMsgText: Sp(""), + ExpectedURN: Sp("instagram:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Icebreaker Get Started", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/icebreakerGetStarted.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + ExpectedURN: Sp("instagram:5678"), + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedChannelEvent: courier.NewConversation, ExpectedChannelEventExtra: map[string]interface{}{"title": "icebreaker question", "payload": "get_started"}, - PrepRequest: addValidSignature}, - {Label: "Different Page", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/differentPageIG.json")), ExpectedStatus: 200, ExpectedResponse: `"data":[]`, PrepRequest: addValidSignature}, - {Label: "Echo", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/echoIG.json")), ExpectedStatus: 200, ExpectedResponse: `ignoring echo`, PrepRequest: addValidSignature}, - {Label: "No Entries", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/noEntriesIG.json")), ExpectedStatus: 400, ExpectedResponse: "no entries found", PrepRequest: addValidSignature}, - {Label: "Not Instagram", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/notInstagram.json")), ExpectedStatus: 400, ExpectedResponse: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notinstagram", PrepRequest: addValidSignature}, - {Label: "No Messaging Entries", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/noMessagingEntriesIG.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", PrepRequest: addValidSignature}, - {Label: "Unknown Messaging Entry", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/unknownMessagingEntryIG.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", PrepRequest: addValidSignature}, - {Label: "Not JSON", URL: "/c/ig/receive", Data: "not JSON", ExpectedStatus: 400, ExpectedResponse: "Error", PrepRequest: addValidSignature}, - {Label: "Invalid URN", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/invalidURNIG.json")), ExpectedStatus: 400, ExpectedResponse: "invalid instagram id", PrepRequest: addValidSignature}, - {Label: "Story Mention", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/storyMentionIG.json")), ExpectedStatus: 200, ExpectedResponse: `ignoring story_mention`, PrepRequest: addValidSignature}, - {Label: "Message unsent", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/unsentMsgIG.json")), ExpectedStatus: 200, ExpectedResponse: `msg deleted`, PrepRequest: addValidSignature}, + PrepRequest: addValidSignature, + }, + { + Label: "Different Page", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/differentPageIG.json")), + ExpectedStatus: 200, + ExpectedResponse: `"data":[]`, + PrepRequest: addValidSignature, + }, + { + Label: "Echo", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/echoIG.json")), + ExpectedStatus: 200, + ExpectedResponse: `ignoring echo`, + PrepRequest: addValidSignature, + }, + { + Label: "No Entries", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/noEntriesIG.json")), + ExpectedStatus: 400, + ExpectedResponse: "no entries found", + PrepRequest: addValidSignature, + }, + { + Label: "Not Instagram", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/notInstagram.json")), + ExpectedStatus: 400, + ExpectedResponse: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notinstagram", + PrepRequest: addValidSignature, + }, + { + Label: "No Messaging Entries", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/noMessagingEntriesIG.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + PrepRequest: addValidSignature, + }, + { + Label: "Unknown Messaging Entry", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/unknownMessagingEntryIG.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + PrepRequest: addValidSignature, + }, + { + Label: "Not JSON", + URL: "/c/ig/receive", + Data: "not JSON", + ExpectedStatus: 400, + ExpectedResponse: "Error", + PrepRequest: addValidSignature, + }, + { + Label: "Invalid URN", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/invalidURNIG.json")), + ExpectedStatus: 400, + ExpectedResponse: "invalid instagram id", + PrepRequest: addValidSignature, + }, + { + Label: "Story Mention", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/storyMentionIG.json")), + ExpectedStatus: 200, + ExpectedResponse: `ignoring story_mention`, + PrepRequest: addValidSignature, + }, + { + Label: "Message unsent", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/unsentMsgIG.json")), + ExpectedStatus: 200, + ExpectedResponse: `msg deleted`, + PrepRequest: addValidSignature, + }, } func addValidSignature(r *http.Request) { - body, _ := handlers.ReadBody(r, 100000) + body, _ := ReadBody(r, 100000) sig, _ := fbCalculateSignature("fb_app_secret", body) r.Header.Set(signatureHeader, fmt.Sprintf("sha1=%s", string(sig))) } @@ -252,51 +532,214 @@ func TestDescribeWAC(t *testing.T) { var wacReceiveURL = "/c/wac/receive" var testCasesWAC = []ChannelHandleTestCase{ - {Label: "Receive Message WAC", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/helloWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), - PrepRequest: addValidSignature}, - {Label: "Receive Duplicate Valid Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/duplicateWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), - PrepRequest: addValidSignature}, - - {Label: "Receive Valid Voice Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/voiceWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp(""), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Voice"}, ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), - PrepRequest: addValidSignature}, - - {Label: "Receive Valid Button Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/buttonWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("No"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), - PrepRequest: addValidSignature}, - - {Label: "Receive Valid Document Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/documentWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("80skaraokesonglistartist"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Document"}, ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), - PrepRequest: addValidSignature}, - {Label: "Receive Valid Image Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/imageWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Check out my new phone!"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Image"}, ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), - PrepRequest: addValidSignature}, - {Label: "Receive Valid Video Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/videoWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Check out my new phone!"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Video"}, ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), - PrepRequest: addValidSignature}, - {Label: "Receive Valid Audio Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/audioWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Check out my new phone!"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Audio"}, ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), - PrepRequest: addValidSignature}, - {Label: "Receive Valid Location Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/locationWAC.json")), ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), - PrepRequest: addValidSignature}, - - {Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: "not json", ExpectedStatus: 400, ExpectedResponse: "unable to parse", PrepRequest: addValidSignature}, - {Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidFrom.json")), ExpectedStatus: 400, ExpectedResponse: "invalid whatsapp id", PrepRequest: addValidSignature}, - {Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidTimestamp.json")), ExpectedStatus: 400, ExpectedResponse: "invalid timestamp", PrepRequest: addValidSignature}, - - {Label: "Receive Valid Status", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/validStatusWAC.json")), ExpectedStatus: 200, ExpectedResponse: `"type":"status"`, - ExpectedMsgStatus: Sp("S"), ExpectedExternalID: Sp("external_id"), PrepRequest: addValidSignature}, - {Label: "Receive Invalid Status", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidStatusWAC.json")), ExpectedStatus: 400, ExpectedResponse: `"unknown status: in_orbit"`, PrepRequest: addValidSignature}, - {Label: "Receive Ignore Status", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/ignoreStatusWAC.json")), ExpectedStatus: 200, ExpectedResponse: `"ignoring status: deleted"`, PrepRequest: addValidSignature}, - {Label: "Receive Valid Interactive Button Reply Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/buttonReplyWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Yes"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), - PrepRequest: addValidSignature}, - {Label: "Receive Valid Interactive List Reply Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/listReplyWAC.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, - ExpectedMsgText: Sp("Yes"), ExpectedURN: Sp("whatsapp:5678"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), - PrepRequest: addValidSignature}, + { + Label: "Receive Message WAC", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/helloWAC.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + NoQueueErrorCheck: true, + NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: Sp("whatsapp:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Duplicate Valid Message", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/duplicateWAC.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + NoQueueErrorCheck: true, + NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: Sp("whatsapp:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Voice Message", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/voiceWAC.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + NoQueueErrorCheck: true, + NoInvalidChannelCheck: true, + ExpectedMsgText: Sp(""), + ExpectedURN: Sp("whatsapp:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Voice"}, + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Button Message", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/buttonWAC.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + NoQueueErrorCheck: true, + NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("No"), + ExpectedURN: Sp("whatsapp:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Document Message", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/documentWAC.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + NoQueueErrorCheck: true, + NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("80skaraokesonglistartist"), + ExpectedURN: Sp("whatsapp:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Document"}, + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Image Message", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/imageWAC.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + NoQueueErrorCheck: true, + NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Check out my new phone!"), + ExpectedURN: Sp("whatsapp:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Image"}, + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Video Message", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/videoWAC.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + NoQueueErrorCheck: true, + NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Check out my new phone!"), + ExpectedURN: Sp("whatsapp:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Video"}, + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Audio Message", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/audioWAC.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + NoQueueErrorCheck: true, + NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Check out my new phone!"), + ExpectedURN: Sp("whatsapp:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Audio"}, + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Location Message", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/locationWAC.json")), + ExpectedStatus: 200, + ExpectedResponse: `"type":"msg"`, + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"geo:0.000000,1.000000"}, + ExpectedURN: Sp("whatsapp:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Invalid JSON", + URL: wacReceiveURL, + Data: "not json", + ExpectedStatus: 400, + ExpectedResponse: "unable to parse", + PrepRequest: addValidSignature, + }, + { + Label: "Receive Invalid JSON", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/invalidFrom.json")), + ExpectedStatus: 400, + ExpectedResponse: "invalid whatsapp id", + PrepRequest: addValidSignature, + }, + { + Label: "Receive Invalid JSON", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/invalidTimestamp.json")), + ExpectedStatus: 400, + ExpectedResponse: "invalid timestamp", + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Status", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/validStatusWAC.json")), + ExpectedStatus: 200, + ExpectedResponse: `"type":"status"`, + ExpectedMsgStatus: Sp("S"), + ExpectedExternalID: Sp("external_id"), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Invalid Status", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/invalidStatusWAC.json")), + ExpectedStatus: 400, + ExpectedResponse: `"unknown status: in_orbit"`, + PrepRequest: addValidSignature, + }, + { + Label: "Receive Ignore Status", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/ignoreStatusWAC.json")), + ExpectedStatus: 200, + ExpectedResponse: `"ignoring status: deleted"`, + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Interactive Button Reply Message", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/buttonReplyWAC.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + NoQueueErrorCheck: true, + NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Yes"), + ExpectedURN: Sp("whatsapp:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Interactive List Reply Message", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/listReplyWAC.json")), + ExpectedStatus: 200, + ExpectedResponse: "Handled", + NoQueueErrorCheck: true, + NoInvalidChannelCheck: true, + ExpectedMsgText: Sp("Yes"), + ExpectedURN: Sp("whatsapp:5678"), + ExpectedExternalID: Sp("external_id"), + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + PrepRequest: addValidSignature, + }, } func TestHandler(t *testing.T) { @@ -360,25 +803,75 @@ func BenchmarkHandler(b *testing.B) { } func TestVerify(t *testing.T) { - RunChannelTestCases(t, testChannelsFBA, newHandler("FBA", "Facebook", false), []ChannelHandleTestCase{ - {Label: "Valid Secret", URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", ExpectedStatus: 200, - ExpectedResponse: "yarchallenge", NoQueueErrorCheck: true, NoInvalidChannelCheck: true}, - {Label: "Verify No Mode", URL: "/c/fba/receive", ExpectedStatus: 400, ExpectedResponse: "unknown request"}, - {Label: "Verify No Secret", URL: "/c/fba/receive?hub.mode=subscribe", ExpectedStatus: 400, ExpectedResponse: "token does not match secret"}, - {Label: "Invalid Secret", URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=blah", ExpectedStatus: 400, ExpectedResponse: "token does not match secret"}, - {Label: "Valid Secret", URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", ExpectedStatus: 200, ExpectedResponse: "yarchallenge"}, + { + Label: "Valid Secret", + URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", + ExpectedStatus: 200, + ExpectedResponse: "yarchallenge", + NoQueueErrorCheck: true, + NoInvalidChannelCheck: true, + }, + { + Label: "Verify No Mode", + URL: "/c/fba/receive", + ExpectedStatus: 400, + ExpectedResponse: "unknown request", + }, + { + Label: "Verify No Secret", + URL: "/c/fba/receive?hub.mode=subscribe", + ExpectedStatus: 400, + ExpectedResponse: "token does not match secret", + }, + { + Label: "Invalid Secret", + URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=blah", + ExpectedStatus: 400, + ExpectedResponse: "token does not match secret", + }, + { + Label: "Valid Secret", + URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", + ExpectedStatus: 200, + ExpectedResponse: "yarchallenge", + }, }) RunChannelTestCases(t, testChannelsIG, newHandler("IG", "Instagram", false), []ChannelHandleTestCase{ - {Label: "Valid Secret", URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", ExpectedStatus: 200, - ExpectedResponse: "yarchallenge", NoQueueErrorCheck: true, NoInvalidChannelCheck: true}, - {Label: "Verify No Mode", URL: "/c/ig/receive", ExpectedStatus: 400, ExpectedResponse: "unknown request"}, - {Label: "Verify No Secret", URL: "/c/ig/receive?hub.mode=subscribe", ExpectedStatus: 400, ExpectedResponse: "token does not match secret"}, - {Label: "Invalid Secret", URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=blah", ExpectedStatus: 400, ExpectedResponse: "token does not match secret"}, - {Label: "Valid Secret", URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", ExpectedStatus: 200, ExpectedResponse: "yarchallenge"}, + { + Label: "Valid Secret", + URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", + ExpectedStatus: 200, + ExpectedResponse: "yarchallenge", + NoQueueErrorCheck: true, + NoInvalidChannelCheck: true, + }, + { + Label: "Verify No Mode", + URL: "/c/ig/receive", + ExpectedStatus: 400, + ExpectedResponse: "unknown request", + }, + { + Label: "Verify No Secret", + URL: "/c/ig/receive?hub.mode=subscribe", + ExpectedStatus: 400, + ExpectedResponse: "token does not match secret", + }, + { + Label: "Invalid Secret", + URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=blah", + ExpectedStatus: 400, + ExpectedResponse: "token does not match secret", + }, + { + Label: "Valid Secret", + URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", + ExpectedStatus: 200, + ExpectedResponse: "yarchallenge", + }, }) - } // setSendURL takes care of setting the send_url to our test server host @@ -901,5 +1394,4 @@ func TestBuildMediaRequest(t *testing.T) { req, _ = igHandler.BuildDownloadMediaRequest(context.Background(), mb, testChannelsFBA[0], "https://example.org/v1/media/41") assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, http.Header{}, req.Header) - } diff --git a/handlers/firebase/firebase_test.go b/handlers/firebase/firebase_test.go index 0a95c7a4b..956a16ce4 100644 --- a/handlers/firebase/firebase_test.go +++ b/handlers/firebase/firebase_test.go @@ -10,15 +10,9 @@ import ( "github.com/nyaruka/courier/test" ) -var ( +const ( receiveURL = "/c/fcm/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive" - validMsg = "from=12345&date=2017-01-01T08:50:00.000&fcm_token=token&name=fred&msg=hello+world" - invalidDate = "from=12345&date=yo&fcm_token=token&name=fred&msg=hello+world" - missingFrom = "date=2017-01-01T08:50:00.000&fcm_token=token&name=fred&msg=hello+world" - - registerURL = "/c/fcm/8eb23e93-5ecb-45ba-b726-3b064e0c568c/register" - validRegister = "urn=12345&fcm_token=token&name=fred" - missingURN = "fcm_token=token&name=fred" + registerURL = "/c/fcm/8eb23e93-5ecb-45ba-b726-3b064e0c568c/register" ) var longMsg = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas convallis augue vel placerat congue. @@ -50,13 +44,46 @@ var testChannels = []courier.Channel{ } var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("fcm:12345"), ExpectedDate: time.Date(2017, 1, 1, 8, 50, 0, 0, time.UTC), ExpectedURNAuth: Sp("token"), ExpectedContactName: Sp("fred")}, - {Label: "Receive Invalid Date", URL: receiveURL, Data: invalidDate, ExpectedStatus: 400, ExpectedResponse: "unable to parse date"}, - {Label: "Receive Missing From", URL: receiveURL, Data: missingFrom, ExpectedStatus: 400, ExpectedResponse: "field 'from' required"}, - - {Label: "Receive Valid Register", URL: registerURL, Data: validRegister, ExpectedStatus: 200, ExpectedResponse: "contact_uuid"}, - {Label: "Receive Missing URN", URL: registerURL, Data: missingURN, ExpectedStatus: 400, ExpectedResponse: "field 'urn' required"}, + { + Label: "Receive Valid Message", + URL: receiveURL, + Data: "from=12345&date=2017-01-01T08:50:00.000&fcm_token=token&name=fred&msg=hello+world", + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("hello world"), + ExpectedURN: Sp("fcm:12345"), + ExpectedDate: time.Date(2017, 1, 1, 8, 50, 0, 0, time.UTC), + ExpectedURNAuth: Sp("token"), + ExpectedContactName: Sp("fred"), + }, + { + Label: "Receive Invalid Date", + URL: receiveURL, + Data: "from=12345&date=yo&fcm_token=token&name=fred&msg=hello+world", + ExpectedStatus: 400, + ExpectedResponse: "unable to parse date", + }, + { + Label: "Receive Missing From", + URL: receiveURL, + Data: "date=2017-01-01T08:50:00.000&fcm_token=token&name=fred&msg=hello+world", + ExpectedStatus: 400, + ExpectedResponse: "field 'from' required", + }, + { + Label: "Receive Valid Register", + URL: registerURL, + Data: "urn=12345&fcm_token=token&name=fred", + ExpectedStatus: 200, + ExpectedResponse: "contact_uuid", + }, + { + Label: "Receive Missing URN", + URL: registerURL, + Data: "fcm_token=token&name=fred", + ExpectedStatus: 400, + ExpectedResponse: "field 'urn' required", + }, } func TestHandler(t *testing.T) { diff --git a/handlers/freshchat/freshchat_test.go b/handlers/freshchat/freshchat_test.go index 7e5deabe9..0409f9cde 100644 --- a/handlers/freshchat/freshchat_test.go +++ b/handlers/freshchat/freshchat_test.go @@ -19,11 +19,10 @@ var testChannels = []courier.Channel{ // author-id } -var ( +const ( cert = "-----BEGIN RSA PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuGJLF4hTTtxWogT6dNkGf3CEgLAR2mGJzlds5cNbrHFoJNFnmVhkRYGzLYxx4EtDiezNCZVHfyMI2AKuNSQW2fEdDatVIG+q3Zr/X9eeDl8kQOGy804J/fgCYDrN8RQu0n5Dh1inv4puca0wb29SCvoAwrWb33ehDBIvv6+rUKBdjtv2xTV65kNiVDo5VRCaYRVeE10osxeONgw55HVY4nczuxnR+dmc2282de6WHe5LXtr0ZBdJ8yttFOLIluZ/sNM5DIWZBkIWQhyT581tbA7bTpsIbrT/IMBlmioIILw8WGtI7zcmNkjU5dnq5HnlVKEDhj/Ug/dLiyno8+Vp7QIDAQAB -----END RSA PUBLIC KEY-----" receiveURL = "/c/fc/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" - notJSON = "empty" validSignature = `AhrmypOSWoewHG6LmIRuWjxyokuMDmPklrSU9p0gpUNjdSRCJzvpL6rjuTi5poV/ZLzWRWNM7X9yWjT5m9YFPshYrvigcd1ph4Ot2xmaJGYoUNJHijQccE6oDtDIp6i/8oLRafHgObQnGukZWPbP9OE5EiKz/VcsMP0Wv7hawI/sfIviM0w+6fNOKXWi0jDBH9ap1mj5CqOUOojni7OD5iYmIrjV/h33dyNmbvAta9E+trzcEhYqxfHIN4Z8R2FsatfRHWicoQ4PE5cQ8+UONVya8qr85nQ9w8N7Ql7yNg9fEViYG4/W/JnGEbPPEf8WrYtKzoVyuupDz4mVHdfKWg==` validReceive = `{"actor":{"actor_type":"user","actor_id":"882f3926-b292-414b-a411-96380db373cd"},"action":"message_create","action_time":"2019-06-21T17:43:20.875Z","data":{"message":{"message_parts":[{"text":{"content":"Test 2"}}],"app_id":"55b190fa-5d3c-45c4-bc49-74ddcfcf53d7","actor_id":"882f3926-b292-414b-a411-96380db373cd","id":"7a454fde-c720-4c97-a61d-0ffe70449eb6","channel_id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606","conversation_id":"c327498e-f713-481e-8d83-0603e03d2521","message_type":"normal","actor_type":"user","created_time":"2019-06-21T17:43:20.866Z"}}}` invalidSignature = `f7wMD1BBhcj60U0z3dCY519qmxQ8qfVUU212Dapw9vpZfRBfjjmukUK2GwbAb0Nc+TGQHxN4iP4WD+Y/mSx6f4bmkBsvCy3l4OCQ/FEK0y5R7f+GLLDhgbTh90MwuLDHhvxB5dxIeu59leL+4yO+l/8M3Tm48aQurVBi9IAlzFsMtc1S1CiRxsDUb/rD6IRekPa0pUAbkno9qJ/CGXh0kZMdsYzRkzZmKCs79OWrvU94ha0ptyt5wArfmD1oSzY3PjeL2w8LWDc0QV21H/Hvj42azIUqebiNRtZ2E+f34AfQsyfcPuy1k/6qLuYGOdU1uZidPuPcGpeSIm0GW6k9HQ==` @@ -67,7 +66,7 @@ var testCases = []ChannelHandleTestCase{ Label: "Bad JSON", Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": invalidSignature}, URL: receiveURL, - Data: notJSON, + Data: "empty", ExpectedStatus: 400, ExpectedResponse: `{"message":"Error","data":[{"type":"error","error":"unable to parse request JSON: invalid character 'e' looking for beginning of value"}]}`, }, diff --git a/handlers/globe/globe_test.go b/handlers/globe/globe_test.go index 55bfd3035..cf75016a8 100644 --- a/handlers/globe/globe_test.go +++ b/handlers/globe/globe_test.go @@ -10,7 +10,7 @@ import ( "github.com/nyaruka/courier/test" ) -var ( +const ( receiveURL = "/c/gl/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive" validMessage = ` @@ -103,8 +103,6 @@ var ( } } ` - - invalidJSON = `notjson` ) var testChannels = []courier.Channel{ @@ -112,13 +110,51 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: validMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+639171234567"), ExpectedDate: time.Date(2013, 11, 22, 12, 12, 13, 0, time.UTC)}, - {Label: "No Messages", URL: receiveURL, Data: noMessages, ExpectedStatus: 200, ExpectedResponse: "Ignored"}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Invalid Sender", URL: receiveURL, Data: invalidSender, ExpectedStatus: 400, ExpectedResponse: "invalid 'senderAddress' parameter"}, - {Label: "Invalid Date", URL: receiveURL, Data: invalidDate, ExpectedStatus: 400, ExpectedResponse: "parsing time"}, - {Label: "Invalid JSON", URL: receiveURL, Data: invalidJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, + { + Label: "Receive Valid Message", + URL: receiveURL, + Data: validMessage, + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("hello world"), + ExpectedURN: Sp("tel:+639171234567"), + ExpectedDate: time.Date(2013, 11, 22, 12, 12, 13, 0, time.UTC), + }, + { + Label: "No Messages", + URL: receiveURL, + Data: noMessages, + ExpectedStatus: 200, + ExpectedResponse: "Ignored", + }, + { + Label: "Invalid URN", + URL: receiveURL, + Data: invalidURN, + ExpectedStatus: 400, + ExpectedResponse: "phone number supplied is not a number", + }, + { + Label: "Invalid Sender", + URL: receiveURL, + Data: invalidSender, + ExpectedStatus: 400, + ExpectedResponse: "invalid 'senderAddress' parameter", + }, + { + Label: "Invalid Date", + URL: receiveURL, + Data: invalidDate, + ExpectedStatus: 400, + ExpectedResponse: "parsing time", + }, + { + Label: "Invalid JSON", + URL: receiveURL, + Data: `notjson`, + ExpectedStatus: 400, + ExpectedResponse: "unable to parse request JSON", + }, } func TestHandler(t *testing.T) { @@ -135,29 +171,46 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var sendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `[{"Response": "0"}]`, + MockResponseStatus: 200, ExpectedRequestBody: `{"address":"250788383383","message":"Simple Message","passphrase":"opensesame","app_id":"12345","app_secret":"mysecret"}`, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: "☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "tel:+250788383383", + MockResponseBody: `[{"Response": "0"}]`, + MockResponseStatus: 200, ExpectedRequestBody: `{"address":"250788383383","message":"☺","passphrase":"opensesame","app_id":"12345","app_secret":"mysecret"}`, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `[{"Response": "0"}]`, + MockResponseStatus: 200, ExpectedRequestBody: `{"address":"250788383383","message":"My pic!\nhttps://foo.bar/image.jpg","passphrase":"opensesame","app_id":"12345","app_secret":"mysecret"}`, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Sending", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `[{"Response": "101"}]`, MockResponseStatus: 403, - SendPrep: setSendURL}, + ExpectedStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Sending", + MsgURN: "tel:+250788383383", + MockResponseBody: `[{"Response": "101"}]`, + MockResponseStatus: 403, + ExpectedStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { From c59623cd015812bb772e895200e8459071492dee Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 29 Aug 2022 12:28:43 -0500 Subject: [PATCH 118/294] Less use of string pointers in tests --- handlers/burstsms/burstsms_test.go | 3 ++- handlers/dart/dart_test.go | 6 +++--- handlers/facebook/facebook_test.go | 2 +- handlers/facebookapp/facebookapp_test.go | 4 ++-- handlers/jasmin/jasmin_test.go | 4 ++-- handlers/junebug/junebug_test.go | 8 ++++---- handlers/kaleyra/kaleyra_test.go | 4 ++-- handlers/mtarget/mtarget_test.go | 4 ++-- handlers/test.go | 8 ++++---- handlers/wavy/wavy_test.go | 8 ++++---- handlers/whatsapp/whatsapp_test.go | 2 +- handlers/zenvia/zenvia_test.go | 8 ++++---- handlers/zenviaold/zenviaold_test.go | 6 +++--- 13 files changed, 34 insertions(+), 33 deletions(-) diff --git a/handlers/burstsms/burstsms_test.go b/handlers/burstsms/burstsms_test.go index 2f64e519d..049cfd4d6 100644 --- a/handlers/burstsms/burstsms_test.go +++ b/handlers/burstsms/burstsms_test.go @@ -39,7 +39,8 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Status Update Accepted", ExpectedExternalID: Sp("12345"), - ExpectedMsgStatus: Sp("S")}, + ExpectedMsgStatus: "S", + }, { Label: "Receive Invalid Status", URL: statusURL + "?message_id=12345&status=unknown", diff --git a/handlers/dart/dart_test.go b/handlers/dart/dart_test.go index 41b4d9563..e700b220b 100644 --- a/handlers/dart/dart_test.go +++ b/handlers/dart/dart_test.go @@ -47,21 +47,21 @@ var daTestCases = []ChannelHandleTestCase{ URL: statusURL + "?status=10&messageid=12345", ExpectedStatus: 200, ExpectedResponse: "000", - ExpectedMsgStatus: Sp("D"), + ExpectedMsgStatus: "D", }, { Label: "Valid Status", URL: statusURL + "?status=10&messageid=12345.2", ExpectedStatus: 200, ExpectedResponse: "000", - ExpectedMsgStatus: Sp("D"), + ExpectedMsgStatus: "D", }, { Label: "Failed Status", URL: statusURL + "?status=30&messageid=12345", ExpectedStatus: 200, ExpectedResponse: "000", - ExpectedMsgStatus: Sp("F"), + ExpectedMsgStatus: "F", }, { Label: "Missing Status", diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index f1abc4191..1e65a9807 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -548,7 +548,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Handled", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedMsgStatus: Sp(courier.MsgDelivered), + ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233"), }, { diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 31a514dae..23244d966 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -182,7 +182,7 @@ var testCasesFBA = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Handled", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedMsgStatus: Sp(courier.MsgDelivered), + ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233"), PrepRequest: addValidSignature, }, @@ -692,7 +692,7 @@ var testCasesWAC = []ChannelHandleTestCase{ Data: string(test.ReadFile("./testdata/wac/validStatusWAC.json")), ExpectedStatus: 200, ExpectedResponse: `"type":"status"`, - ExpectedMsgStatus: Sp("S"), + ExpectedMsgStatus: "S", ExpectedExternalID: Sp("external_id"), PrepRequest: addValidSignature, }, diff --git a/handlers/jasmin/jasmin_test.go b/handlers/jasmin/jasmin_test.go index c561934e2..2b0714483 100644 --- a/handlers/jasmin/jasmin_test.go +++ b/handlers/jasmin/jasmin_test.go @@ -34,9 +34,9 @@ var handleTestCases = []ChannelHandleTestCase{ {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Status Delivered", URL: statusURL, Data: statusDelivered, ExpectedStatus: 200, ExpectedResponse: "ACK/Jasmin", - ExpectedMsgStatus: Sp("D"), ExpectedExternalID: Sp("external1")}, + ExpectedMsgStatus: "D", ExpectedExternalID: Sp("external1")}, {Label: "Status Failed", URL: statusURL, Data: statusFailed, ExpectedStatus: 200, ExpectedResponse: "ACK/Jasmin", - ExpectedMsgStatus: Sp("F"), ExpectedExternalID: Sp("external1")}, + ExpectedMsgStatus: "F", ExpectedExternalID: Sp("external1")}, {Label: "Status Missing", URL: statusURL, ExpectedStatus: 400, Data: "nothing", ExpectedResponse: "field 'id' required"}, {Label: "Status Unknown", URL: statusURL, ExpectedStatus: 400, Data: statusUnknown, diff --git a/handlers/junebug/junebug_test.go b/handlers/junebug/junebug_test.go index b40d8e73b..b4eb7331f 100644 --- a/handlers/junebug/junebug_test.go +++ b/handlers/junebug/junebug_test.go @@ -106,11 +106,11 @@ var testCases = []ChannelHandleTestCase{ {Label: "Receive Pending Event", URL: eventURL, Data: pendingEvent, ExpectedStatus: 200, ExpectedResponse: "Ignored"}, {Label: "Receive Sent Event", URL: eventURL, Data: sentEvent, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedExternalID: Sp("xx12345"), ExpectedMsgStatus: Sp("S")}, + ExpectedExternalID: Sp("xx12345"), ExpectedMsgStatus: "S"}, {Label: "Receive Delivered Event", URL: eventURL, Data: deliveredEvent, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedExternalID: Sp("xx12345"), ExpectedMsgStatus: Sp("D")}, + ExpectedExternalID: Sp("xx12345"), ExpectedMsgStatus: "D"}, {Label: "Receive Failed Event", URL: eventURL, Data: failedEvent, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedExternalID: Sp("xx12345"), ExpectedMsgStatus: Sp("F")}, + ExpectedExternalID: Sp("xx12345"), ExpectedMsgStatus: "F"}, {Label: "Receive Unknown Event", URL: eventURL, Data: unknownEvent, ExpectedStatus: 200, ExpectedResponse: "Ignored"}, {Label: "Receive Invalid JSON", URL: eventURL, Data: "not json", ExpectedStatus: 400, ExpectedResponse: "Error"}, @@ -128,7 +128,7 @@ var authenticatedTestCases = []ChannelHandleTestCase{ {Label: "Receive Sent Event", URL: eventURL, Data: sentEvent, Headers: map[string]string{"Authorization": "Token sesame"}, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedExternalID: Sp("xx12345"), ExpectedMsgStatus: Sp("S")}, + ExpectedExternalID: Sp("xx12345"), ExpectedMsgStatus: "S"}, {Label: "Invalid Incoming Authorization", URL: eventURL, Data: sentEvent, Headers: map[string]string{"Authorization": "Token foo"}, ExpectedStatus: 401, ExpectedResponse: "Unauthorized"}, } diff --git a/handlers/kaleyra/kaleyra_test.go b/handlers/kaleyra/kaleyra_test.go index 23451738d..36e0bd3a1 100644 --- a/handlers/kaleyra/kaleyra_test.go +++ b/handlers/kaleyra/kaleyra_test.go @@ -84,7 +84,7 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive Valid Status", URL: receiveStatusURL + "?id=58f86fab-85c5-4f7c-9b68-9c323248afc4%3A0&status=read", ExpectedExternalID: Sp("58f86fab-85c5-4f7c-9b68-9c323248afc4:0"), - ExpectedMsgStatus: Sp("D"), + ExpectedMsgStatus: "D", ExpectedStatus: 200, ExpectedResponse: `"type":"status"`, }, @@ -92,7 +92,7 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive Invalid Status", URL: receiveStatusURL + "?id=58f86fab-85c5-4f7c-9b68-9c323248afc4%3A0&status=deleted", ExpectedExternalID: Sp("58f86fab-85c5-4f7c-9b68-9c323248afc4:0"), - ExpectedMsgStatus: Sp("D"), + ExpectedMsgStatus: "D", ExpectedStatus: 200, ExpectedResponse: "unknown status", }, diff --git a/handlers/mtarget/mtarget_test.go b/handlers/mtarget/mtarget_test.go index 83052878f..71cbe1b78 100644 --- a/handlers/mtarget/mtarget_test.go +++ b/handlers/mtarget/mtarget_test.go @@ -44,9 +44,9 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+923161909799")}, {Label: "Status Delivered", URL: statusURL, Data: statusDelivered, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedExternalID: Sp("12a7ee90-50ce-11e7-80ae-00000a0a643c"), ExpectedMsgStatus: Sp("D")}, + ExpectedExternalID: Sp("12a7ee90-50ce-11e7-80ae-00000a0a643c"), ExpectedMsgStatus: "D"}, {Label: "Status Failed", URL: statusURL, Data: statusFailed, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedExternalID: Sp("12a7ee90-50ce-11e7-80ae-00000a0a643c"), ExpectedMsgStatus: Sp("F")}, + ExpectedExternalID: Sp("12a7ee90-50ce-11e7-80ae-00000a0a643c"), ExpectedMsgStatus: "F"}, {Label: "Status Missing ID", URL: statusURL, Data: statusMissingID, ExpectedStatus: 400, ExpectedResponse: "missing required field 'MsgId'"}, } diff --git a/handlers/test.go b/handlers/test.go index bb5f22acb..110f5bddd 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -45,7 +45,7 @@ type ChannelHandleTestCase struct { ExpectedURNAuth *string ExpectedAttachments []string ExpectedDate time.Time - ExpectedMsgStatus *string + ExpectedMsgStatus courier.MsgStatusValue ExpectedExternalID *string ExpectedMsgID int64 @@ -401,9 +401,9 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri require.Equal(*tc.ExpectedExternalID, "") } } - if tc.ExpectedMsgStatus != nil { + if tc.ExpectedMsgStatus != "" { require.NotNil(status) - require.Equal(*tc.ExpectedMsgStatus, string(status.Status())) + require.Equal(tc.ExpectedMsgStatus, status.Status()) } if tc.ExpectedMsgID != 0 { if status != nil { @@ -427,7 +427,7 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri } // if we're expecting a message, status or event, check we have a log for it - if tc.ExpectedMsgText != nil || tc.ExpectedMsgStatus != nil || tc.ExpectedChannelEvent != "" { + if tc.ExpectedMsgText != nil || tc.ExpectedMsgStatus != "" || tc.ExpectedChannelEvent != "" { assert.Greater(t, len(mb.ChannelLogs()), 0, "expected at least one channel log") } }) diff --git a/handlers/wavy/wavy_test.go b/handlers/wavy/wavy_test.go index acd02542a..36535f78d 100644 --- a/handlers/wavy/wavy_test.go +++ b/handlers/wavy/wavy_test.go @@ -84,13 +84,13 @@ var testCases = []ChannelHandleTestCase{ {Label: "Invalid JSON receive", URL: receiveURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, {Label: "Missing Keys receive", URL: receiveURL, Data: missingRequiredKeys, ExpectedStatus: 400, ExpectedResponse: "validation for 'ID' failed on the 'required'"}, - {Label: "Sent Status Valid", URL: sentStatusURL, Data: validSentStatus, ExpectedStatus: 200, ExpectedResponse: "Status Update Accepted", ExpectedMsgStatus: Sp(courier.MsgSent)}, - {Label: "Unknown Sent Status Valid", URL: sentStatusURL, Data: unknownSentStatus, ExpectedStatus: 400, ExpectedResponse: "unknown sent status code", ExpectedMsgStatus: Sp(courier.MsgWired)}, + {Label: "Sent Status Valid", URL: sentStatusURL, Data: validSentStatus, ExpectedStatus: 200, ExpectedResponse: "Status Update Accepted", ExpectedMsgStatus: courier.MsgSent}, + {Label: "Unknown Sent Status Valid", URL: sentStatusURL, Data: unknownSentStatus, ExpectedStatus: 400, ExpectedResponse: "unknown sent status code", ExpectedMsgStatus: courier.MsgWired}, {Label: "Invalid JSON sent Status", URL: sentStatusURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, {Label: "Missing Keys sent Status", URL: sentStatusURL, Data: missingRequiredKeys, ExpectedStatus: 400, ExpectedResponse: "validation for 'CollerationID' failed on the 'required'"}, - {Label: "Delivered Status Valid", URL: deliveredStatusURL, Data: validDeliveredStatus, ExpectedStatus: 200, ExpectedResponse: "Status Update Accepted", ExpectedMsgStatus: Sp(courier.MsgDelivered)}, - {Label: "Unknown Delivered Status Valid", URL: deliveredStatusURL, Data: unknownDeliveredStatus, ExpectedStatus: 400, ExpectedResponse: "unknown delivered status code", ExpectedMsgStatus: Sp(courier.MsgSent)}, + {Label: "Delivered Status Valid", URL: deliveredStatusURL, Data: validDeliveredStatus, ExpectedStatus: 200, ExpectedResponse: "Status Update Accepted", ExpectedMsgStatus: courier.MsgDelivered}, + {Label: "Unknown Delivered Status Valid", URL: deliveredStatusURL, Data: unknownDeliveredStatus, ExpectedStatus: 400, ExpectedResponse: "unknown delivered status code", ExpectedMsgStatus: courier.MsgSent}, {Label: "Invalid JSON delivered Statu", URL: deliveredStatusURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, {Label: "Missing Keys sent Status", URL: deliveredStatusURL, Data: missingRequiredKeys, ExpectedStatus: 400, ExpectedResponse: "validation for 'CollerationID' failed on the 'required'"}, } diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index 1762dbbca..fee7fd879 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -319,7 +319,7 @@ var waTestCases = []ChannelHandleTestCase{ {Label: "Receive Invalid Timestamp", URL: waReceiveURL, Data: invalidTimestamp, ExpectedStatus: 400, ExpectedResponse: "invalid timestamp"}, {Label: "Receive Valid Status", URL: waReceiveURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `"type":"status"`, - ExpectedMsgStatus: Sp("S"), ExpectedExternalID: Sp("9712A34B4A8B6AD50F")}, + ExpectedMsgStatus: "S", ExpectedExternalID: Sp("9712A34B4A8B6AD50F")}, {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: "not json", ExpectedStatus: 400, ExpectedResponse: "unable to parse"}, {Label: "Receive Invalid Status", URL: waReceiveURL, Data: invalidStatus, ExpectedStatus: 400, ExpectedResponse: `"unknown status: in_orbit"`}, {Label: "Receive Ignore Status", URL: waReceiveURL, Data: ignoreStatus, ExpectedStatus: 200, ExpectedResponse: `"ignoring status: deleted"`}, diff --git a/handlers/zenvia/zenvia_test.go b/handlers/zenvia/zenvia_test.go index 41abb6222..62a75a956 100644 --- a/handlers/zenvia/zenvia_test.go +++ b/handlers/zenvia/zenvia_test.go @@ -210,8 +210,8 @@ var testWhatappCases = []ChannelHandleTestCase{ {Label: "Missing field", URL: receiveWhatsappURL, Data: missingFieldsReceive, ExpectedStatus: 400, ExpectedResponse: "validation for 'ID' failed on the 'required'"}, {Label: "Bad Date", URL: receiveWhatsappURL, Data: invalidDateReceive, ExpectedStatus: 400, ExpectedResponse: "invalid date format"}, - {Label: "Valid Status", URL: statusWhatsppURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `Accepted`, ExpectedMsgStatus: Sp("S")}, - {Label: "Unkown Status", URL: statusWhatsppURL, Data: unknownStatus, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgStatus: Sp("E")}, + {Label: "Valid Status", URL: statusWhatsppURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `Accepted`, ExpectedMsgStatus: "S"}, + {Label: "Unkown Status", URL: statusWhatsppURL, Data: unknownStatus, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgStatus: "E"}, {Label: "Not JSON body", URL: statusWhatsppURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, {Label: "Wrong JSON schema", URL: statusWhatsppURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, } @@ -231,8 +231,8 @@ var testSMSCases = []ChannelHandleTestCase{ {Label: "Missing field", URL: receiveSMSURL, Data: missingFieldsReceive, ExpectedStatus: 400, ExpectedResponse: "validation for 'ID' failed on the 'required'"}, {Label: "Bad Date", URL: receiveSMSURL, Data: invalidDateReceive, ExpectedStatus: 400, ExpectedResponse: "invalid date format"}, - {Label: "Valid Status", URL: statusSMSURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `Accepted`, ExpectedMsgStatus: Sp("S")}, - {Label: "Unkown Status", URL: statusSMSURL, Data: unknownStatus, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgStatus: Sp("E")}, + {Label: "Valid Status", URL: statusSMSURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `Accepted`, ExpectedMsgStatus: "S"}, + {Label: "Unkown Status", URL: statusSMSURL, Data: unknownStatus, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgStatus: "E"}, {Label: "Not JSON body", URL: statusSMSURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, {Label: "Wrong JSON schema", URL: statusSMSURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, } diff --git a/handlers/zenviaold/zenviaold_test.go b/handlers/zenviaold/zenviaold_test.go index 47eb9b3a1..34a459da6 100644 --- a/handlers/zenviaold/zenviaold_test.go +++ b/handlers/zenviaold/zenviaold_test.go @@ -114,9 +114,9 @@ var testCases = []ChannelHandleTestCase{ {Label: "Missing field", URL: receiveURL, Data: missingFieldsReceive, ExpectedStatus: 400, ExpectedResponse: "validation for 'ID' failed on the 'required'"}, {Label: "Bad Date", URL: receiveURL, Data: invalidDateReceive, ExpectedStatus: 400, ExpectedResponse: "invalid date format"}, - {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `Accepted`, ExpectedMsgStatus: Sp("D")}, - {Label: "Valid Status with more fields", URL: statusURL, Data: validWithMoreFieldsStatus, ExpectedStatus: 200, ExpectedResponse: `Accepted`, ExpectedMsgStatus: Sp("D")}, - {Label: "Unkown Status", URL: statusURL, Data: unknownStatus, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgStatus: Sp("E")}, + {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `Accepted`, ExpectedMsgStatus: "D"}, + {Label: "Valid Status with more fields", URL: statusURL, Data: validWithMoreFieldsStatus, ExpectedStatus: 200, ExpectedResponse: `Accepted`, ExpectedMsgStatus: "D"}, + {Label: "Unkown Status", URL: statusURL, Data: unknownStatus, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgStatus: "E"}, {Label: "Not JSON body", URL: statusURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, {Label: "Wrong JSON schema", URL: statusURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, {Label: "Missing field", URL: statusURL, Data: missingFieldsStatus, ExpectedStatus: 400, ExpectedResponse: "validation for 'StatusCode' failed on the 'required'"}, From ed9c691653950209eafe52e86ea188f425c77fc5 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 29 Aug 2022 14:00:47 -0500 Subject: [PATCH 119/294] Don't use string pointers in handler tests for things where empty string is the zero value --- .../africastalking/africastalking_test.go | 8 +- handlers/arabiacell/arabiacell_test.go | 2 +- handlers/blackmyna/blackmyna_test.go | 2 +- handlers/bongolive/bongolive_test.go | 4 +- handlers/burstsms/burstsms_test.go | 4 +- handlers/chikka/chikka_test.go | 4 +- handlers/clickatell/clickatell_test.go | 12 +-- handlers/clickmobile/clickmobile_test.go | 27 +++-- handlers/clicksend/clicksend_test.go | 2 +- handlers/dart/dart_test.go | 4 +- handlers/discord/discord_test.go | 4 +- handlers/dmark/dmark_test.go | 2 +- handlers/external/external_test.go | 20 ++-- handlers/facebook/facebook_test.go | 34 +++---- handlers/facebookapp/facebookapp_test.go | 98 +++++++++---------- handlers/firebase/firebase_test.go | 4 +- handlers/freshchat/freshchat_test.go | 4 +- handlers/globe/globe_test.go | 2 +- .../highconnection/highconnection_test.go | 17 ++-- handlers/hormuud/hormuud_test.go | 4 +- handlers/i2sms/i2sms_test.go | 24 +++-- handlers/infobip/infobip_test.go | 2 +- handlers/jasmin/jasmin_test.go | 6 +- handlers/jiochat/jiochat_test.go | 6 +- handlers/junebug/junebug_test.go | 12 +-- handlers/kaleyra/kaleyra_test.go | 10 +- handlers/kannel/kannel_test.go | 8 +- handlers/line/line_test.go | 14 +-- handlers/m3tech/m3tech_test.go | 33 +++++-- handlers/macrokiosk/macrokiosk_test.go | 12 +-- handlers/mblox/mblox_test.go | 4 +- handlers/messangi/messangi_test.go | 22 +++-- handlers/mtarget/mtarget_test.go | 10 +- handlers/nexmo/nexmo_test.go | 16 +-- handlers/novo/novo_test.go | 2 +- handlers/playmobile/playmobile_test.go | 50 +++++----- handlers/plivo/plivo_test.go | 2 +- handlers/rocketchat/rocketchat_test.go | 4 +- handlers/shaqodoon/shaqodoon_test.go | 10 +- handlers/slack/slack_test.go | 16 +-- handlers/smscentral/smscentral_test.go | 55 ++++++++--- handlers/start/start_test.go | 8 +- handlers/telegram/telegram_test.go | 20 ++-- handlers/telesom/telesom_test.go | 4 +- handlers/test.go | 28 +++--- handlers/thinq/thinq_test.go | 71 ++++++++++---- handlers/twiml/twiml_test.go | 70 ++++++------- handlers/twitter/twitter_test.go | 6 +- handlers/viber/viber_test.go | 12 +-- handlers/vk/vk_test.go | 36 +++---- handlers/wavy/wavy_test.go | 2 +- handlers/wechat/wechat_test.go | 6 +- handlers/whatsapp/whatsapp_test.go | 24 ++--- handlers/yo/yo_test.go | 8 +- handlers/zenvia/zenvia_test.go | 12 +-- handlers/zenviaold/zenviaold_test.go | 2 +- 56 files changed, 488 insertions(+), 397 deletions(-) diff --git a/handlers/africastalking/africastalking_test.go b/handlers/africastalking/africastalking_test.go index 0070972d7..1d64b9999 100644 --- a/handlers/africastalking/africastalking_test.go +++ b/handlers/africastalking/africastalking_test.go @@ -27,8 +27,8 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Message Accepted", ExpectedMsgText: Sp("Msg"), - ExpectedURN: Sp("tel:+254791541111"), - ExpectedExternalID: Sp("ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3"), + ExpectedURN: "tel:+254791541111", + ExpectedExternalID: "ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3", ExpectedDate: time.Date(2017, 5, 3, 06, 04, 45, 0, time.UTC), }, { @@ -38,8 +38,8 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Message Accepted", ExpectedMsgText: Sp("Msg"), - ExpectedURN: Sp("tel:+254791541111"), - ExpectedExternalID: Sp("ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3"), + ExpectedURN: "tel:+254791541111", + ExpectedExternalID: "ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3", ExpectedDate: time.Date(2017, 5, 3, 06, 04, 45, 0, time.UTC), }, { diff --git a/handlers/arabiacell/arabiacell_test.go b/handlers/arabiacell/arabiacell_test.go index 5276fb3a7..8d74da833 100644 --- a/handlers/arabiacell/arabiacell_test.go +++ b/handlers/arabiacell/arabiacell_test.go @@ -25,7 +25,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Message Accepted", ExpectedMsgText: Sp("Msg"), - ExpectedURN: Sp("tel:+254791541111"), + ExpectedURN: "tel:+254791541111", }, { Label: "Receive Missing Number", diff --git a/handlers/blackmyna/blackmyna_test.go b/handlers/blackmyna/blackmyna_test.go index 61f6e1dcc..4d158d610 100644 --- a/handlers/blackmyna/blackmyna_test.go +++ b/handlers/blackmyna/blackmyna_test.go @@ -25,7 +25,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Message Accepted", ExpectedMsgText: Sp("Msg"), - ExpectedURN: Sp("tel:+9779814641111"), + ExpectedURN: "tel:+9779814641111", }, { Label: "Invalid URN", diff --git a/handlers/bongolive/bongolive_test.go b/handlers/bongolive/bongolive_test.go index 1eea920cf..297a51b11 100644 --- a/handlers/bongolive/bongolive_test.go +++ b/handlers/bongolive/bongolive_test.go @@ -25,7 +25,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "", ExpectedMsgText: Sp("Msg"), - ExpectedURN: Sp("tel:+254791541111"), + ExpectedURN: "tel:+254791541111", }, { Label: "Receive Valid", @@ -34,7 +34,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "", ExpectedMsgText: Sp("Msg"), - ExpectedURN: Sp("tel:+254791541111"), + ExpectedURN: "tel:+254791541111", }, { Label: "Receive Missing Number", diff --git a/handlers/burstsms/burstsms_test.go b/handlers/burstsms/burstsms_test.go index 049cfd4d6..adcb4ea45 100644 --- a/handlers/burstsms/burstsms_test.go +++ b/handlers/burstsms/burstsms_test.go @@ -25,7 +25,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Message Accepted", ExpectedMsgText: Sp("Msg"), - ExpectedURN: Sp("tel:+254791541111"), + ExpectedURN: "tel:+254791541111", }, { Label: "Receive Missing Number", @@ -38,7 +38,7 @@ var testCases = []ChannelHandleTestCase{ URL: statusURL + "?message_id=12345&status=pending", ExpectedStatus: 200, ExpectedResponse: "Status Update Accepted", - ExpectedExternalID: Sp("12345"), + ExpectedExternalID: "12345", ExpectedMsgStatus: "S", }, { diff --git a/handlers/chikka/chikka_test.go b/handlers/chikka/chikka_test.go index 0fcfecca1..12b0d13cc 100644 --- a/handlers/chikka/chikka_test.go +++ b/handlers/chikka/chikka_test.go @@ -26,8 +26,8 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Message Accepted", ExpectedMsgText: Sp("Hello World"), - ExpectedURN: Sp("tel:+639178020779"), - ExpectedExternalID: Sp("4004"), + ExpectedURN: "tel:+639178020779", + ExpectedExternalID: "4004", ExpectedDate: time.Date(2016, 03, 11, 04, 20, 59, 690000128, time.UTC), }, { diff --git a/handlers/clickatell/clickatell_test.go b/handlers/clickatell/clickatell_test.go index e9f55ede6..19b38ea2f 100644 --- a/handlers/clickatell/clickatell_test.go +++ b/handlers/clickatell/clickatell_test.go @@ -138,8 +138,8 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("Hello World!"), - ExpectedURN: Sp("tel:+250788383383"), - ExpectedExternalID: Sp("1234"), + ExpectedURN: "tel:+250788383383", + ExpectedExternalID: "1234", ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC), }, { @@ -149,8 +149,8 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp(`hello!`), - ExpectedURN: Sp("tel:+250788383383"), - ExpectedExternalID: Sp("1234"), + ExpectedURN: "tel:+250788383383", + ExpectedExternalID: "1234", ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC), }, { @@ -181,8 +181,8 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("mexico k mis papas no tenýa dinero para comprarnos lo q querýamos.."), - ExpectedURN: Sp("tel:+250788383383"), - ExpectedExternalID: Sp("1234"), + ExpectedURN: "tel:+250788383383", + ExpectedExternalID: "1234", ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC), }, { diff --git a/handlers/clickmobile/clickmobile_test.go b/handlers/clickmobile/clickmobile_test.go index cbcea2906..e68317af5 100644 --- a/handlers/clickmobile/clickmobile_test.go +++ b/handlers/clickmobile/clickmobile_test.go @@ -72,8 +72,8 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("Join"), - ExpectedURN: Sp("tel:+265990099333"), - ExpectedExternalID: Sp("1232434354"), + ExpectedURN: "tel:+265990099333", + ExpectedExternalID: "1232434354", }, { Label: "Invalid URN", @@ -89,8 +89,8 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp(""), - ExpectedURN: Sp("tel:+265990099333"), - ExpectedExternalID: Sp("1232434354"), + ExpectedURN: "tel:+265990099333", + ExpectedExternalID: "1232434354", }, { Label: "Receive valid missing text", @@ -99,18 +99,17 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp(""), - ExpectedURN: Sp("tel:+265990099333"), - ExpectedExternalID: Sp("1232434354"), + ExpectedURN: "tel:+265990099333", + ExpectedExternalID: "1232434354", }, { - Label: "Receive valid missing referenceID", - URL: receiveURL, - Data: validMissingReferenceID, - ExpectedStatus: 200, - ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: Sp("tel:+265990099333"), - ExpectedExternalID: Sp(""), + Label: "Receive valid missing referenceID", + URL: receiveURL, + Data: validMissingReferenceID, + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+265990099333", }, { Label: "Missing Shortcode", diff --git a/handlers/clicksend/clicksend_test.go b/handlers/clicksend/clicksend_test.go index cf52719a7..f553421ca 100644 --- a/handlers/clicksend/clicksend_test.go +++ b/handlers/clicksend/clicksend_test.go @@ -26,7 +26,7 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("hello world"), - ExpectedURN: Sp("tel:+639171234567"), + ExpectedURN: "tel:+639171234567", }, { Label: "Receive Missing From", diff --git a/handlers/dart/dart_test.go b/handlers/dart/dart_test.go index e700b220b..98a59c222 100644 --- a/handlers/dart/dart_test.go +++ b/handlers/dart/dart_test.go @@ -25,7 +25,7 @@ var daTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "000", ExpectedMsgText: Sp("Msg"), - ExpectedURN: Sp("tel:+6289881134560"), + ExpectedURN: "tel:+6289881134560", }, { Label: "Receive Valid", @@ -33,7 +33,7 @@ var daTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "000", ExpectedMsgText: Sp("Msg"), - ExpectedURN: Sp("ext:cmp-oodddqddwdwdcd"), + ExpectedURN: "ext:cmp-oodddqddwdwdcd", }, { Label: "Receive Invalid", diff --git a/handlers/discord/discord_test.go b/handlers/discord/discord_test.go index e38289328..abe04cbe4 100644 --- a/handlers/discord/discord_test.go +++ b/handlers/discord/discord_test.go @@ -29,7 +29,7 @@ var testCases = []ChannelHandleTestCase{ Data: `from=694634743521607802&text=hello`, ExpectedStatus: 200, ExpectedMsgText: Sp("hello"), - ExpectedURN: Sp("discord:694634743521607802"), + ExpectedURN: "discord:694634743521607802", }, { Label: "Recieve Message with attachment", @@ -37,7 +37,7 @@ var testCases = []ChannelHandleTestCase{ Data: `from=694634743521607802&text=hello&attachments=https://test.test/foo.png`, ExpectedStatus: 200, ExpectedMsgText: Sp("hello"), - ExpectedURN: Sp("discord:694634743521607802"), + ExpectedURN: "discord:694634743521607802", ExpectedAttachments: []string{"https://test.test/foo.png"}, }, { diff --git a/handlers/dmark/dmark_test.go b/handlers/dmark/dmark_test.go index f6e714d61..257e46369 100644 --- a/handlers/dmark/dmark_test.go +++ b/handlers/dmark/dmark_test.go @@ -27,7 +27,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Message Accepted", ExpectedMsgText: Sp("Msg"), - ExpectedURN: Sp("tel:+254791541111"), + ExpectedURN: "tel:+254791541111", ExpectedDate: time.Date(2017, 10, 26, 15, 51, 32, 906335000, time.UTC), }, { diff --git a/handlers/external/external_test.go b/handlers/external/external_test.go index 72f0c6094..cae2f1a82 100644 --- a/handlers/external/external_test.go +++ b/handlers/external/external_test.go @@ -32,7 +32,7 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("Join"), - ExpectedURN: Sp("tel:+2349067554729"), + ExpectedURN: "tel:+2349067554729", }, { Label: "Receive Valid Post", @@ -41,7 +41,7 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("Join"), - ExpectedURN: Sp("tel:+2349067554729"), + ExpectedURN: "tel:+2349067554729", }, { Label: "Receive Valid Post multipart form", @@ -50,7 +50,7 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("Join"), - ExpectedURN: Sp("tel:+2349067554729"), + ExpectedURN: "tel:+2349067554729", }, { Label: "Receive Valid From", @@ -59,7 +59,7 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("Join"), - ExpectedURN: Sp("tel:+2349067554729"), + ExpectedURN: "tel:+2349067554729", }, { Label: "Receive Country Parse", @@ -68,7 +68,7 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("Join"), - ExpectedURN: Sp("tel:+2349067554729"), + ExpectedURN: "tel:+2349067554729", }, { Label: "Receive Valid Message With Date", @@ -77,7 +77,7 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("Join"), - ExpectedURN: Sp("tel:+2349067554729"), + ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC), }, { @@ -87,7 +87,7 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("Join"), - ExpectedURN: Sp("tel:+2349067554729"), + ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC), }, { @@ -202,7 +202,7 @@ var handleSOAPReceiveTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "0", ExpectedMsgText: Sp("Join"), - ExpectedURN: Sp("tel:+2349067554729"), + ExpectedURN: "tel:+2349067554729", }, { Label: "Receive Invalid SOAP", @@ -221,7 +221,7 @@ var gmTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("Join"), - ExpectedURN: Sp("tel:+2207222333"), + ExpectedURN: "tel:+2207222333", }, } @@ -243,7 +243,7 @@ var customTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("Join"), - ExpectedURN: Sp("tel:+12067799192"), + ExpectedURN: "tel:+12067799192", ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC), }, { diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index 1e65a9807..6f61ad1e0 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -425,8 +425,8 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Handled", ExpectedMsgText: Sp("Hello World"), - ExpectedURN: Sp("facebook:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), }, { @@ -436,8 +436,8 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Handled", ExpectedMsgText: Sp("Hello World"), - ExpectedURN: Sp("facebook:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), }, { @@ -448,8 +448,8 @@ var testCases = []ChannelHandleTestCase{ ExpectedResponse: "Handled", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, - ExpectedURN: Sp("facebook:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), }, { @@ -460,8 +460,8 @@ var testCases = []ChannelHandleTestCase{ ExpectedResponse: "Handled", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, - ExpectedURN: Sp("facebook:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), }, { @@ -471,8 +471,8 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Handled", ExpectedMsgText: Sp("👍"), - ExpectedURN: Sp("facebook:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), }, { @@ -481,7 +481,7 @@ var testCases = []ChannelHandleTestCase{ Data: optInUserRef, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:ref:optin_user_ref"), + ExpectedURN: "facebook:ref:optin_user_ref", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, @@ -492,7 +492,7 @@ var testCases = []ChannelHandleTestCase{ Data: optIn, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), + ExpectedURN: "facebook:5678", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, @@ -503,7 +503,7 @@ var testCases = []ChannelHandleTestCase{ Data: postbackGetStarted, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), + ExpectedURN: "facebook:5678", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.NewConversation, ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, @@ -514,7 +514,7 @@ var testCases = []ChannelHandleTestCase{ Data: postback, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), + ExpectedURN: "facebook:5678", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, @@ -525,7 +525,7 @@ var testCases = []ChannelHandleTestCase{ Data: postbackReferral, ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), + ExpectedURN: "facebook:5678", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, @@ -536,7 +536,7 @@ var testCases = []ChannelHandleTestCase{ Data: referral, ExpectedStatus: 200, ExpectedResponse: `"referrer_id":"referral id"`, - ExpectedURN: Sp("facebook:5678"), + ExpectedURN: "facebook:5678", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, @@ -549,7 +549,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedResponse: "Handled", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedMsgStatus: courier.MsgDelivered, - ExpectedExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233"), + ExpectedExternalID: "mid.1458668856218:ed81099e15d3f4f233", }, { Label: "Different Page", diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 23244d966..d9002948d 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -40,8 +40,8 @@ var testCasesFBA = []ChannelHandleTestCase{ NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Hello World"), - ExpectedURN: Sp("facebook:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature, }, @@ -60,8 +60,8 @@ var testCasesFBA = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Handled", ExpectedMsgText: Sp("Hello World"), - ExpectedURN: Sp("facebook:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature, }, @@ -73,8 +73,8 @@ var testCasesFBA = []ChannelHandleTestCase{ ExpectedResponse: "Handled", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, - ExpectedURN: Sp("facebook:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature, }, @@ -86,8 +86,8 @@ var testCasesFBA = []ChannelHandleTestCase{ ExpectedResponse: "Handled", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, - ExpectedURN: Sp("facebook:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature, }, @@ -98,8 +98,8 @@ var testCasesFBA = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Handled", ExpectedMsgText: Sp("👍"), - ExpectedURN: Sp("facebook:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature, }, @@ -109,7 +109,7 @@ var testCasesFBA = []ChannelHandleTestCase{ Data: string(test.ReadFile("./testdata/fba/optInUserRef.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:ref:optin_user_ref"), + ExpectedURN: "facebook:ref:optin_user_ref", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, @@ -121,7 +121,7 @@ var testCasesFBA = []ChannelHandleTestCase{ Data: string(test.ReadFile("./testdata/fba/optIn.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), + ExpectedURN: "facebook:5678", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, @@ -133,7 +133,7 @@ var testCasesFBA = []ChannelHandleTestCase{ Data: string(test.ReadFile("./testdata/fba/postbackGetStarted.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), + ExpectedURN: "facebook:5678", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.NewConversation, ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, @@ -145,7 +145,7 @@ var testCasesFBA = []ChannelHandleTestCase{ Data: string(test.ReadFile("./testdata/fba/postback.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), + ExpectedURN: "facebook:5678", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, @@ -157,7 +157,7 @@ var testCasesFBA = []ChannelHandleTestCase{ Data: string(test.ReadFile("./testdata/fba/postbackReferral.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("facebook:5678"), + ExpectedURN: "facebook:5678", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, @@ -169,7 +169,7 @@ var testCasesFBA = []ChannelHandleTestCase{ Data: string(test.ReadFile("./testdata/fba/referral.json")), ExpectedStatus: 200, ExpectedResponse: `"referrer_id":"referral id"`, - ExpectedURN: Sp("facebook:5678"), + ExpectedURN: "facebook:5678", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.Referral, ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, @@ -183,7 +183,7 @@ var testCasesFBA = []ChannelHandleTestCase{ ExpectedResponse: "Handled", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedMsgStatus: courier.MsgDelivered, - ExpectedExternalID: Sp("mid.1458668856218:ed81099e15d3f4f233"), + ExpectedExternalID: "mid.1458668856218:ed81099e15d3f4f233", PrepRequest: addValidSignature, }, { @@ -262,8 +262,8 @@ var testCasesIG = []ChannelHandleTestCase{ NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Hello World"), - ExpectedURN: Sp("instagram:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "instagram:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature, }, @@ -282,8 +282,8 @@ var testCasesIG = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Handled", ExpectedMsgText: Sp("Hello World"), - ExpectedURN: Sp("instagram:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "instagram:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature, }, @@ -295,8 +295,8 @@ var testCasesIG = []ChannelHandleTestCase{ ExpectedResponse: "Handled", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, - ExpectedURN: Sp("instagram:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "instagram:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature, }, @@ -307,8 +307,8 @@ var testCasesIG = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Handled", ExpectedMsgText: Sp(""), - ExpectedURN: Sp("instagram:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "instagram:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature, }, @@ -318,7 +318,7 @@ var testCasesIG = []ChannelHandleTestCase{ Data: string(test.ReadFile("./testdata/ig/icebreakerGetStarted.json")), ExpectedStatus: 200, ExpectedResponse: "Handled", - ExpectedURN: Sp("instagram:5678"), + ExpectedURN: "instagram:5678", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedChannelEvent: courier.NewConversation, ExpectedChannelEventExtra: map[string]interface{}{"title": "icebreaker question", "payload": "get_started"}, @@ -541,8 +541,8 @@ var testCasesWAC = []ChannelHandleTestCase{ NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Hello World"), - ExpectedURN: Sp("whatsapp:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "whatsapp:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature, }, @@ -555,8 +555,8 @@ var testCasesWAC = []ChannelHandleTestCase{ NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Hello World"), - ExpectedURN: Sp("whatsapp:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "whatsapp:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature, }, @@ -569,8 +569,8 @@ var testCasesWAC = []ChannelHandleTestCase{ NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp(""), - ExpectedURN: Sp("whatsapp:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "whatsapp:5678", + ExpectedExternalID: "external_id", ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Voice"}, ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature, @@ -584,8 +584,8 @@ var testCasesWAC = []ChannelHandleTestCase{ NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("No"), - ExpectedURN: Sp("whatsapp:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "whatsapp:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature, }, @@ -598,8 +598,8 @@ var testCasesWAC = []ChannelHandleTestCase{ NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("80skaraokesonglistartist"), - ExpectedURN: Sp("whatsapp:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "whatsapp:5678", + ExpectedExternalID: "external_id", ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Document"}, ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature, @@ -613,8 +613,8 @@ var testCasesWAC = []ChannelHandleTestCase{ NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Check out my new phone!"), - ExpectedURN: Sp("whatsapp:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "whatsapp:5678", + ExpectedExternalID: "external_id", ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Image"}, ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature, @@ -628,8 +628,8 @@ var testCasesWAC = []ChannelHandleTestCase{ NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Check out my new phone!"), - ExpectedURN: Sp("whatsapp:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "whatsapp:5678", + ExpectedExternalID: "external_id", ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Video"}, ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature, @@ -643,8 +643,8 @@ var testCasesWAC = []ChannelHandleTestCase{ NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Check out my new phone!"), - ExpectedURN: Sp("whatsapp:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "whatsapp:5678", + ExpectedExternalID: "external_id", ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Audio"}, ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature, @@ -657,8 +657,8 @@ var testCasesWAC = []ChannelHandleTestCase{ ExpectedResponse: `"type":"msg"`, ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, - ExpectedURN: Sp("whatsapp:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "whatsapp:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature, }, @@ -693,7 +693,7 @@ var testCasesWAC = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: `"type":"status"`, ExpectedMsgStatus: "S", - ExpectedExternalID: Sp("external_id"), + ExpectedExternalID: "external_id", PrepRequest: addValidSignature, }, { @@ -721,8 +721,8 @@ var testCasesWAC = []ChannelHandleTestCase{ NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Yes"), - ExpectedURN: Sp("whatsapp:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "whatsapp:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature, }, @@ -735,8 +735,8 @@ var testCasesWAC = []ChannelHandleTestCase{ NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Yes"), - ExpectedURN: Sp("whatsapp:5678"), - ExpectedExternalID: Sp("external_id"), + ExpectedURN: "whatsapp:5678", + ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), PrepRequest: addValidSignature, }, diff --git a/handlers/firebase/firebase_test.go b/handlers/firebase/firebase_test.go index 956a16ce4..c2c67d120 100644 --- a/handlers/firebase/firebase_test.go +++ b/handlers/firebase/firebase_test.go @@ -51,9 +51,9 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("hello world"), - ExpectedURN: Sp("fcm:12345"), + ExpectedURN: "fcm:12345", ExpectedDate: time.Date(2017, 1, 1, 8, 50, 0, 0, time.UTC), - ExpectedURNAuth: Sp("token"), + ExpectedURNAuth: "token", ExpectedContactName: Sp("fred"), }, { diff --git a/handlers/freshchat/freshchat_test.go b/handlers/freshchat/freshchat_test.go index 0409f9cde..30f1d04a1 100644 --- a/handlers/freshchat/freshchat_test.go +++ b/handlers/freshchat/freshchat_test.go @@ -37,7 +37,7 @@ var sigtestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Message Accepted", ExpectedMsgText: Sp("Test 2"), - ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), + ExpectedURN: "freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd", ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC), }, { @@ -59,7 +59,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Message Accepted", ExpectedMsgText: Sp("Test 2"), - ExpectedURN: Sp("freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd"), + ExpectedURN: "freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd", ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC), }, { diff --git a/handlers/globe/globe_test.go b/handlers/globe/globe_test.go index cf75016a8..12233dc19 100644 --- a/handlers/globe/globe_test.go +++ b/handlers/globe/globe_test.go @@ -117,7 +117,7 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgText: Sp("hello world"), - ExpectedURN: Sp("tel:+639171234567"), + ExpectedURN: "tel:+639171234567", ExpectedDate: time.Date(2013, 11, 22, 12, 12, 13, 0, time.UTC), }, { diff --git a/handlers/highconnection/highconnection_test.go b/handlers/highconnection/highconnection_test.go index 3f83af7d6..49f4953ae 100644 --- a/handlers/highconnection/highconnection_test.go +++ b/handlers/highconnection/highconnection_test.go @@ -26,13 +26,16 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("tel:+33610346460"), - ExpectedDate: time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC)}, - {Label: "Receive Valid Message with accents", URL: receiveURL, Data: validAccentReceive, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("je suis très satisfait "), ExpectedURN: Sp("tel:+33610346460"), - ExpectedDate: time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC)}, - + { + Label: "Receive Valid Message", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Hello World"), ExpectedURN: "tel:+33610346460", + ExpectedDate: time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC), + }, + { + Label: "Receive Valid Message with accents", URL: receiveURL, Data: validAccentReceive, ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("je suis très satisfait "), ExpectedURN: "tel:+33610346460", + ExpectedDate: time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC), + }, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Receive Missing Params", URL: receiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: "validation for 'From' failed"}, {Label: "Receive Invalid Date", URL: receiveURL, Data: invalidDateReceive, ExpectedStatus: 400, ExpectedResponse: "cannot parse"}, diff --git a/handlers/hormuud/hormuud_test.go b/handlers/hormuud/hormuud_test.go index 2b31ad0a7..0a91322b2 100644 --- a/handlers/hormuud/hormuud_test.go +++ b/handlers/hormuud/hormuud_test.go @@ -27,9 +27,9 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, + ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, + ExpectedMsgText: Sp(""), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'sender' required"}, {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, // {Label: "Status No Params", URL: statusNoParams, Status: 400, Response: "field 'status' required"}, diff --git a/handlers/i2sms/i2sms_test.go b/handlers/i2sms/i2sms_test.go index 86345e572..b82194ceb 100644 --- a/handlers/i2sms/i2sms_test.go +++ b/handlers/i2sms/i2sms_test.go @@ -13,17 +13,27 @@ var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "I2", "2020", "US", nil), } -var ( +const ( receiveURL = "/c/i2/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" - - validReceive = "message=Msg&mobile=254791541111" - missingNumber = "message=Msg" ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111")}, - {Label: "Receive Missing Number", URL: receiveURL, Data: missingNumber, ExpectedStatus: 400, ExpectedResponse: "required field 'mobile'"}, + { + Label: "Receive Valid", + URL: receiveURL, + Data: "message=Msg&mobile=254791541111", + ExpectedStatus: 200, + ExpectedResponse: "", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+254791541111", + }, + { + Label: "Receive Missing Number", + URL: receiveURL, + Data: "message=Msg", + ExpectedStatus: 400, + ExpectedResponse: "required field 'mobile'", + }, } func TestHandler(t *testing.T) { diff --git a/handlers/infobip/infobip_test.go b/handlers/infobip/infobip_test.go index f35864685..b43131ea7 100644 --- a/handlers/infobip/infobip_test.go +++ b/handlers/infobip/infobip_test.go @@ -192,7 +192,7 @@ var invalidStatus = `{ var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveURL, Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("QUIZ Correct answer is Paris"), ExpectedURN: Sp("tel:+385916242493"), ExpectedExternalID: Sp("817790313235066447"), ExpectedDate: time.Date(2016, 10, 06, 9, 28, 39, 220000000, time.FixedZone("", 0))}, + ExpectedMsgText: Sp("QUIZ Correct answer is Paris"), ExpectedURN: "tel:+385916242493", ExpectedExternalID: "817790313235066447", ExpectedDate: time.Date(2016, 10, 06, 9, 28, 39, 220000000, time.FixedZone("", 0))}, {Label: "Receive missing results key", URL: receiveURL, Data: missingResults, ExpectedStatus: 400, ExpectedResponse: "validation for 'Results' failed"}, {Label: "Receive missing text key", URL: receiveURL, Data: missingText, ExpectedStatus: 200, ExpectedResponse: "ignoring request, no message"}, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, diff --git a/handlers/jasmin/jasmin_test.go b/handlers/jasmin/jasmin_test.go index 2b0714483..fbcdb9102 100644 --- a/handlers/jasmin/jasmin_test.go +++ b/handlers/jasmin/jasmin_test.go @@ -28,15 +28,15 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "ACK/Jasmin", - ExpectedMsgText: Sp("événement"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedExternalID: Sp("1001")}, + ExpectedMsgText: Sp("événement"), ExpectedURN: "tel:+2349067554729", ExpectedExternalID: "1001"}, {Label: "Receive Missing To", URL: receiveURL, Data: receiveMissingTo, ExpectedStatus: 400, ExpectedResponse: "field 'to' required"}, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Status Delivered", URL: statusURL, Data: statusDelivered, ExpectedStatus: 200, ExpectedResponse: "ACK/Jasmin", - ExpectedMsgStatus: "D", ExpectedExternalID: Sp("external1")}, + ExpectedMsgStatus: "D", ExpectedExternalID: "external1"}, {Label: "Status Failed", URL: statusURL, Data: statusFailed, ExpectedStatus: 200, ExpectedResponse: "ACK/Jasmin", - ExpectedMsgStatus: "F", ExpectedExternalID: Sp("external1")}, + ExpectedMsgStatus: "F", ExpectedExternalID: "external1"}, {Label: "Status Missing", URL: statusURL, ExpectedStatus: 400, Data: "nothing", ExpectedResponse: "field 'id' required"}, {Label: "Status Unknown", URL: statusURL, ExpectedStatus: 400, Data: statusUnknown, diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index 522f47826..57b8ade4a 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -147,7 +147,7 @@ func addInvalidSignature(r *http.Request) { var testCases = []ChannelHandleTestCase{ {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Simple Message"), ExpectedURN: Sp("jiochat:1234"), ExpectedExternalID: Sp("123456"), + ExpectedMsgText: Sp("Simple Message"), ExpectedURN: "jiochat:1234", ExpectedExternalID: "123456", ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "invalid jiochat id"}, @@ -155,12 +155,12 @@ var testCases = []ChannelHandleTestCase{ {Label: "Missing params Event or MsgId", URL: receiveURL, Data: missingParams, ExpectedStatus: 400, ExpectedResponse: "missing parameters, must have either 'MsgId' or 'Event'"}, {Label: "Receive Image", URL: receiveURL, Data: imageMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedURN: Sp("jiochat:1234"), ExpectedExternalID: Sp("123456"), + ExpectedMsgText: Sp(""), ExpectedURN: "jiochat:1234", ExpectedExternalID: "123456", ExpectedAttachments: []string{"https://channels.jiochat.com/media/download.action?media_id=12"}, ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedStatus: 200, ExpectedResponse: "Event Accepted", - ExpectedChannelEvent: courier.NewConversation, ExpectedURN: Sp("jiochat:1234")}, + ExpectedChannelEvent: courier.NewConversation, ExpectedURN: "jiochat:1234"}, {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, ExpectedStatus: 200, ExpectedResponse: "unknown event"}, diff --git a/handlers/junebug/junebug_test.go b/handlers/junebug/junebug_test.go index b4eb7331f..132ca447e 100644 --- a/handlers/junebug/junebug_test.go +++ b/handlers/junebug/junebug_test.go @@ -94,7 +94,7 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: inboundURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+250788383383"), + ExpectedMsgText: Sp("hello world"), ExpectedURN: "tel:+250788383383", ExpectedDate: time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC)}, {Label: "Invalid URN", URL: inboundURL, Data: invalidURN, @@ -106,11 +106,11 @@ var testCases = []ChannelHandleTestCase{ {Label: "Receive Pending Event", URL: eventURL, Data: pendingEvent, ExpectedStatus: 200, ExpectedResponse: "Ignored"}, {Label: "Receive Sent Event", URL: eventURL, Data: sentEvent, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedExternalID: Sp("xx12345"), ExpectedMsgStatus: "S"}, + ExpectedExternalID: "xx12345", ExpectedMsgStatus: "S"}, {Label: "Receive Delivered Event", URL: eventURL, Data: deliveredEvent, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedExternalID: Sp("xx12345"), ExpectedMsgStatus: "D"}, + ExpectedExternalID: "xx12345", ExpectedMsgStatus: "D"}, {Label: "Receive Failed Event", URL: eventURL, Data: failedEvent, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedExternalID: Sp("xx12345"), ExpectedMsgStatus: "F"}, + ExpectedExternalID: "xx12345", ExpectedMsgStatus: "F"}, {Label: "Receive Unknown Event", URL: eventURL, Data: unknownEvent, ExpectedStatus: 200, ExpectedResponse: "Ignored"}, {Label: "Receive Invalid JSON", URL: eventURL, Data: "not json", ExpectedStatus: 400, ExpectedResponse: "Error"}, @@ -120,7 +120,7 @@ var testCases = []ChannelHandleTestCase{ var authenticatedTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: inboundURL, Data: validMsg, Headers: map[string]string{"Authorization": "Token sesame"}, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+250788383383"), + ExpectedMsgText: Sp("hello world"), ExpectedURN: "tel:+250788383383", ExpectedDate: time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC)}, {Label: "Invalid Incoming Authorization", URL: inboundURL, Data: validMsg, Headers: map[string]string{"Authorization": "Token foo"}, @@ -128,7 +128,7 @@ var authenticatedTestCases = []ChannelHandleTestCase{ {Label: "Receive Sent Event", URL: eventURL, Data: sentEvent, Headers: map[string]string{"Authorization": "Token sesame"}, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedExternalID: Sp("xx12345"), ExpectedMsgStatus: "S"}, + ExpectedExternalID: "xx12345", ExpectedMsgStatus: "S"}, {Label: "Invalid Incoming Authorization", URL: eventURL, Data: sentEvent, Headers: map[string]string{"Authorization": "Token foo"}, ExpectedStatus: 401, ExpectedResponse: "Unauthorized"}, } diff --git a/handlers/kaleyra/kaleyra_test.go b/handlers/kaleyra/kaleyra_test.go index 36e0bd3a1..78dfdfabd 100644 --- a/handlers/kaleyra/kaleyra_test.go +++ b/handlers/kaleyra/kaleyra_test.go @@ -32,7 +32,7 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive Msg", URL: receiveMsgURL + "?created_at=1603914166&type=text&from=14133881111&name=John%20Cruz&body=Hello%20World", ExpectedContactName: Sp("John Cruz"), - ExpectedURN: Sp("whatsapp:14133881111"), + ExpectedURN: "whatsapp:14133881111", ExpectedMsgText: Sp("Hello World"), ExpectedAttachments: []string{}, ExpectedStatus: 200, @@ -42,7 +42,7 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive Media", URL: receiveMsgURL + "?created_at=1603914166&type=image&from=14133881111&name=John%20Cruz&media_url=https://link.to/image.jpg", ExpectedContactName: Sp("John Cruz"), - ExpectedURN: Sp("whatsapp:14133881111"), + ExpectedURN: "whatsapp:14133881111", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://link.to/image.jpg"}, ExpectedStatus: 200, @@ -83,7 +83,7 @@ var testCases = []ChannelHandleTestCase{ { Label: "Receive Valid Status", URL: receiveStatusURL + "?id=58f86fab-85c5-4f7c-9b68-9c323248afc4%3A0&status=read", - ExpectedExternalID: Sp("58f86fab-85c5-4f7c-9b68-9c323248afc4:0"), + ExpectedExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", ExpectedMsgStatus: "D", ExpectedStatus: 200, ExpectedResponse: `"type":"status"`, @@ -91,7 +91,7 @@ var testCases = []ChannelHandleTestCase{ { Label: "Receive Invalid Status", URL: receiveStatusURL + "?id=58f86fab-85c5-4f7c-9b68-9c323248afc4%3A0&status=deleted", - ExpectedExternalID: Sp("58f86fab-85c5-4f7c-9b68-9c323248afc4:0"), + ExpectedExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", ExpectedMsgStatus: "D", ExpectedStatus: 200, ExpectedResponse: "unknown status", @@ -99,7 +99,7 @@ var testCases = []ChannelHandleTestCase{ { Label: "Receive Blank status", URL: receiveStatusURL, - ExpectedExternalID: Sp("58f86fab-85c5-4f7c-9b68-9c323248afc4:0"), + ExpectedExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", ExpectedStatus: 400, ExpectedResponse: "field 'status' required", }, diff --git a/handlers/kannel/kannel_test.go b/handlers/kannel/kannel_test.go index 6cbf30b6d..f3b7384e1 100644 --- a/handlers/kannel/kannel_test.go +++ b/handlers/kannel/kannel_test.go @@ -33,11 +33,11 @@ var ignoreChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedExternalID: Sp("asdf-asdf"), ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, + ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, {Label: "Receive KI Message", URL: receiveKIMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+68673076228"), ExpectedExternalID: Sp("asdf-asdf"), ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, + ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+68673076228", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+2349067554729"), ExpectedExternalID: Sp("asdf-asdf"), ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, + ExpectedMsgText: Sp(""), ExpectedURN: "tel:+2349067554729", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'sender' required"}, {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Status No Params", URL: statusNoParams, ExpectedStatus: 400, ExpectedResponse: "field 'status' required"}, @@ -47,7 +47,7 @@ var handleTestCases = []ChannelHandleTestCase{ var ignoreTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedExternalID: Sp("asdf-asdf"), ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, + ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, {Label: "Write Status Delivered", URL: statusDelivered, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`}, {Label: "Ignore Status Wired", URL: statusWired, ExpectedStatus: 200, ExpectedResponse: `ignoring sent report`}, {Label: "Ignore Status Sent", URL: statusSent, ExpectedStatus: 200, ExpectedResponse: `ignoring sent report`}, diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index cfa984e9d..0fb76a10b 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -259,26 +259,26 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Hello, world"), ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedMsgText: Sp("Hello, world"), ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessageLast, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Last event"), ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedMsgText: Sp("Last event"), ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Image Message", URL: receiveURL, Data: receiveValidImageMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Video Message", URL: receiveURL, Data: receiveValidVideoMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Video External Message", URL: receiveURL, Data: receiveValidVideoExternalMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://example.com/original.mp4"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://example.com/original.mp4"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Audio Message", URL: receiveURL, Data: receiveValidAudioMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Receive Valid Location Message", URL: receiveURL, Data: receiveValidLocationMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("my location"), ExpectedAttachments: []string{"geo:35.687574,139.729220"}, ExpectedURN: Sp("line:uabcdefghij"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedMsgText: Sp("my location"), ExpectedAttachments: []string{"geo:35.687574,139.729220"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, {Label: "Missing message", URL: receiveURL, Data: missingMessage, ExpectedStatus: 200, ExpectedResponse: "ignoring request, no message", diff --git a/handlers/m3tech/m3tech_test.go b/handlers/m3tech/m3tech_test.go index 4e4be31e6..aeacb5a37 100644 --- a/handlers/m3tech/m3tech_test.go +++ b/handlers/m3tech/m3tech_test.go @@ -9,21 +9,34 @@ import ( "github.com/nyaruka/courier/test" ) -var ( - receiveValidMessage = "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?from=+923161909799&text=hello+world" - receiveInvalidURN = "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?from=MTN&text=hello+world" - receiveMissingFrom = "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?text=hello" -) - var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "M3", "2020", "US", nil), } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: " ", ExpectedStatus: 200, ExpectedResponse: "SMS Accepted", - ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+923161909799")}, - {Label: "Invalid URN", URL: receiveInvalidURN, Data: " ", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Receive No From", URL: receiveMissingFrom, Data: " ", ExpectedStatus: 400, ExpectedResponse: "missing required field 'from'"}, + { + Label: "Receive Valid Message", + URL: "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?from=+923161909799&text=hello+world", + Data: " ", + ExpectedStatus: 200, + ExpectedResponse: "SMS Accepted", + ExpectedMsgText: Sp("hello world"), + ExpectedURN: "tel:+923161909799", + }, + { + Label: "Invalid URN", + URL: "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?from=MTN&text=hello+world", + Data: " ", + ExpectedStatus: 400, + ExpectedResponse: "phone number supplied is not a number", + }, + { + Label: "Receive No From", + URL: "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?text=hello", + Data: " ", + ExpectedStatus: 400, + ExpectedResponse: "missing required field 'from'", + }, } func TestHandler(t *testing.T) { diff --git a/handlers/macrokiosk/macrokiosk_test.go b/handlers/macrokiosk/macrokiosk_test.go index dcf1af5b1..f3da52bca 100644 --- a/handlers/macrokiosk/macrokiosk_test.go +++ b/handlers/macrokiosk/macrokiosk_test.go @@ -32,14 +32,14 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "-1", - ExpectedMsgText: Sp("Hello"), ExpectedURN: Sp("tel:+60124361111"), ExpectedDate: time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC), - ExpectedExternalID: Sp("abc1234")}, + ExpectedMsgText: Sp("Hello"), ExpectedURN: "tel:+60124361111", ExpectedDate: time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC), + ExpectedExternalID: "abc1234"}, {Label: "Receive Valid via GET", URL: receiveURL + "?" + validReceive, ExpectedStatus: 200, ExpectedResponse: "-1", - ExpectedMsgText: Sp("Hello"), ExpectedURN: Sp("tel:+60124361111"), ExpectedDate: time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC), - ExpectedExternalID: Sp("abc1234")}, + ExpectedMsgText: Sp("Hello"), ExpectedURN: "tel:+60124361111", ExpectedDate: time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC), + ExpectedExternalID: "abc1234"}, {Label: "Receive Valid", URL: receiveURL, Data: validLongcodeReceive, ExpectedStatus: 200, ExpectedResponse: "-1", - ExpectedMsgText: Sp("Hello"), ExpectedURN: Sp("tel:+60124361111"), ExpectedDate: time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC), - ExpectedExternalID: Sp("abc1234")}, + ExpectedMsgText: Sp("Hello"), ExpectedURN: "tel:+60124361111", ExpectedDate: time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC), + ExpectedExternalID: "abc1234"}, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Missing Params", URL: receiveURL, Data: missingParamsReceive, ExpectedStatus: 400, ExpectedResponse: "missing shortcode, longcode, from or msisdn parameters"}, {Label: "Invalid Params", URL: receiveURL, Data: invalidParamsReceive, ExpectedStatus: 400, ExpectedResponse: "missing shortcode, longcode, from or msisdn parameters"}, diff --git a/handlers/mblox/mblox_test.go b/handlers/mblox/mblox_test.go index ecec6f604..768a35e3d 100644 --- a/handlers/mblox/mblox_test.go +++ b/handlers/mblox/mblox_test.go @@ -63,8 +63,8 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("tel:+12067799294"), ExpectedDate: time.Date(2016, 3, 30, 19, 33, 06, 643000000, time.UTC), - ExpectedExternalID: Sp("OzQ5UqIOdoY8")}, + ExpectedMsgText: Sp("Hello World"), ExpectedURN: "tel:+12067799294", ExpectedDate: time.Date(2016, 3, 30, 19, 33, 06, 643000000, time.UTC), + ExpectedExternalID: "OzQ5UqIOdoY8"}, {Label: "Receive Missing Params", URL: receiveURL, Data: missingParamsRecieve, ExpectedStatus: 400, ExpectedResponse: "missing one of 'id', 'from', 'to', 'body' or 'received_at' in request body"}, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, diff --git a/handlers/messangi/messangi_test.go b/handlers/messangi/messangi_test.go index 4a8750770..49e62c321 100644 --- a/handlers/messangi/messangi_test.go +++ b/handlers/messangi/messangi_test.go @@ -13,17 +13,25 @@ var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "MG", "2020", "JM", nil), } -var ( +const ( receiveURL = "/c/mg/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" - - validReceive = "mo=Msg&mobile=18765422035" - missingNumber = "mo=Msg" ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+18765422035")}, - {Label: "Receive Missing Number", URL: receiveURL, Data: missingNumber, ExpectedStatus: 400, ExpectedResponse: "required field 'mobile'"}, + { + Label: "Receive Valid", + URL: receiveURL, + Data: "mo=Msg&mobile=18765422035", + ExpectedStatus: 200, + ExpectedResponse: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+18765422035"}, + { + Label: "Receive Missing Number", + URL: receiveURL, + Data: "mo=Msg", + ExpectedStatus: 400, + ExpectedResponse: "required field 'mobile'"}, } func TestHandler(t *testing.T) { diff --git a/handlers/mtarget/mtarget_test.go b/handlers/mtarget/mtarget_test.go index 71cbe1b78..44beb94cf 100644 --- a/handlers/mtarget/mtarget_test.go +++ b/handlers/mtarget/mtarget_test.go @@ -33,20 +33,20 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+923161909799")}, + ExpectedMsgText: Sp("hello world"), ExpectedURN: "tel:+923161909799"}, {Label: "Invalid URN", URL: receiveURL, Data: receiveInvalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Receive Stop", URL: receiveURL, Data: receiveStop, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedURN: Sp("tel:+923161909799"), ExpectedChannelEvent: courier.StopContact}, + ExpectedURN: "tel:+923161909799", ExpectedChannelEvent: courier.StopContact}, {Label: "Receive Missing From", URL: receiveURL, Data: receiveMissingFrom, ExpectedStatus: 400, ExpectedResponse: "missing required field 'Msisdn'"}, {Label: "Receive Part 2", URL: receiveURL, Data: receivePart2, ExpectedStatus: 200, ExpectedResponse: "received"}, {Label: "Receive Part 1", URL: receiveURL, Data: receivePart1, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+923161909799")}, + ExpectedMsgText: Sp("hello world"), ExpectedURN: "tel:+923161909799"}, {Label: "Status Delivered", URL: statusURL, Data: statusDelivered, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedExternalID: Sp("12a7ee90-50ce-11e7-80ae-00000a0a643c"), ExpectedMsgStatus: "D"}, + ExpectedExternalID: "12a7ee90-50ce-11e7-80ae-00000a0a643c", ExpectedMsgStatus: "D"}, {Label: "Status Failed", URL: statusURL, Data: statusFailed, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedExternalID: Sp("12a7ee90-50ce-11e7-80ae-00000a0a643c"), ExpectedMsgStatus: "F"}, + ExpectedExternalID: "12a7ee90-50ce-11e7-80ae-00000a0a643c", ExpectedMsgStatus: "F"}, {Label: "Status Missing ID", URL: statusURL, Data: statusMissingID, ExpectedStatus: 400, ExpectedResponse: "missing required field 'MsgId'"}, } diff --git a/handlers/nexmo/nexmo_test.go b/handlers/nexmo/nexmo_test.go index f4856a4f1..779dfe750 100644 --- a/handlers/nexmo/nexmo_test.go +++ b/handlers/nexmo/nexmo_test.go @@ -31,19 +31,19 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Valid Receive", URL: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, {Label: "Invalid URN", URL: receiveInvalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Valid Receive Post", URL: receiveURL, ExpectedStatus: 200, ExpectedResponse: "Accepted", Data: receiveValidMessageBody, - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, {Label: "Receive URL check", URL: receiveURL, ExpectedStatus: 200, ExpectedResponse: "no to parameter, ignored"}, {Label: "Status URL check", URL: statusURL, ExpectedStatus: 200, ExpectedResponse: "no messageId parameter, ignored"}, - {Label: "Status delivered", URL: statusDelivered, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("external1")}, - {Label: "Status expired", URL: statusExpired, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, ExpectedExternalID: Sp("external1")}, - {Label: "Status failed", URL: statusFailed, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, ExpectedExternalID: Sp("external1")}, - {Label: "Status accepted", URL: statusAccepted, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`, ExpectedExternalID: Sp("external1")}, - {Label: "Status buffered", URL: statusBuffered, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`, ExpectedExternalID: Sp("external1")}, - {Label: "Status unexpected", URL: statusUnexpected, ExpectedStatus: 200, ExpectedResponse: "ignoring unknown status report", ExpectedExternalID: Sp("external1")}, + {Label: "Status delivered", URL: statusDelivered, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "external1"}, + {Label: "Status expired", URL: statusExpired, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, ExpectedExternalID: "external1"}, + {Label: "Status failed", URL: statusFailed, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, ExpectedExternalID: "external1"}, + {Label: "Status accepted", URL: statusAccepted, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`, ExpectedExternalID: "external1"}, + {Label: "Status buffered", URL: statusBuffered, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`, ExpectedExternalID: "external1"}, + {Label: "Status unexpected", URL: statusUnexpected, ExpectedStatus: 200, ExpectedResponse: "ignoring unknown status report", ExpectedExternalID: "external1"}, } func TestHandler(t *testing.T) { diff --git a/handlers/novo/novo_test.go b/handlers/novo/novo_test.go index 9e72ef668..23d0916d3 100644 --- a/handlers/novo/novo_test.go +++ b/handlers/novo/novo_test.go @@ -30,7 +30,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedStatus: 200, ExpectedResponse: "Message Accepted", ExpectedMsgText: Sp("Msg"), - ExpectedURN: Sp("tel:+18686846481"), + ExpectedURN: "tel:+18686846481", }, { Label: "Receive Missing Number", diff --git a/handlers/playmobile/playmobile_test.go b/handlers/playmobile/playmobile_test.go index 873464cf4..6f8f4ed3a 100644 --- a/handlers/playmobile/playmobile_test.go +++ b/handlers/playmobile/playmobile_test.go @@ -57,20 +57,6 @@ var ( ] }` - missingRecipient = `{ - "messages": [ - { - "message-id": "2018-10-26-09-27-34", - "sms": { - "originator": "1122", - "content": { - "text": "Message from Paul" - } - } - } - ] - }` - missingMessageID = `{ "messages": [ { @@ -87,40 +73,52 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", + { + Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedResponse: "Accepted", ExpectedStatus: 200, ExpectedMsgText: Sp("SMS Response Accepted"), - ExpectedURN: Sp("tel:+998999999999")}, - {Label: "Receive Missing MSISDN", + ExpectedURN: "tel:+998999999999", + }, + { + Label: "Receive Missing MSISDN", URL: receiveURL, Data: invalidReceive, ExpectedResponse: "missing required fields msidsn or id", - ExpectedStatus: 400}, - {Label: "No Messages", + ExpectedStatus: 400, + }, + { + Label: "No Messages", URL: receiveURL, Data: noMessages, ExpectedResponse: "no messages, ignored", - ExpectedStatus: 200}, - {Label: "Invalid XML", + ExpectedStatus: 200, + }, + { + Label: "Invalid XML", URL: receiveURL, Data: invalidXML, ExpectedResponse: "", - ExpectedStatus: 405}, - {Label: "Receive With Prefix", + ExpectedStatus: 405, + }, + { + Label: "Receive With Prefix", URL: receiveURL, Data: receiveWithPrefix, ExpectedResponse: "Accepted", ExpectedStatus: 200, ExpectedMsgText: Sp("SMS Response Accepted"), - ExpectedURN: Sp("tel:+998999999999")}, - {Label: "Receive With Prefix Only", + ExpectedURN: "tel:+998999999999", + }, + { + Label: "Receive With Prefix Only", URL: receiveURL, Data: receiveWithPrefixOnly, ExpectedResponse: "no text", - ExpectedStatus: 400}, + ExpectedStatus: 400, + }, } func TestHandler(t *testing.T) { diff --git a/handlers/plivo/plivo_test.go b/handlers/plivo/plivo_test.go index 0729eb64c..6ec036b1b 100644 --- a/handlers/plivo/plivo_test.go +++ b/handlers/plivo/plivo_test.go @@ -30,7 +30,7 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Hello"), ExpectedURN: Sp("tel:+60124361111"), ExpectedExternalID: Sp("abc1234")}, + ExpectedMsgText: Sp("Hello"), ExpectedURN: "tel:+60124361111", ExpectedExternalID: "abc1234"}, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Invalid Address Params", URL: receiveURL, Data: invalidAddress, ExpectedStatus: 400, ExpectedResponse: "invalid to number [1515], expecting [2020]"}, {Label: "Missing Params", URL: receiveURL, Data: missingParams, ExpectedStatus: 400, ExpectedResponse: "Field validation for 'To' failed"}, diff --git a/handlers/rocketchat/rocketchat_test.go b/handlers/rocketchat/rocketchat_test.go index f0247a3ea..66f4c345e 100644 --- a/handlers/rocketchat/rocketchat_test.go +++ b/handlers/rocketchat/rocketchat_test.go @@ -57,7 +57,7 @@ var testCases = []handlers.ChannelHandleTestCase{ "Authorization": "Token 123456789", }, Data: helloMsg, - ExpectedURN: handlers.Sp("rocketchat:direct:john.doe#john.doe"), + ExpectedURN: "rocketchat:direct:john.doe#john.doe", ExpectedMsgText: handlers.Sp("Hello World"), ExpectedStatus: 200, ExpectedResponse: "Accepted", @@ -69,7 +69,7 @@ var testCases = []handlers.ChannelHandleTestCase{ "Authorization": "Token 123456789", }, Data: attachmentMsg, - ExpectedURN: handlers.Sp("rocketchat:livechat:onrMgdKbpX9Qqtvoi"), + ExpectedURN: "rocketchat:livechat:onrMgdKbpX9Qqtvoi", ExpectedAttachments: []string{"https://link.to/image.jpg"}, ExpectedStatus: 200, ExpectedResponse: "Accepted", diff --git a/handlers/shaqodoon/shaqodoon_test.go b/handlers/shaqodoon/shaqodoon_test.go index 36f15f6a8..90c69df15 100644 --- a/handlers/shaqodoon/shaqodoon_test.go +++ b/handlers/shaqodoon/shaqodoon_test.go @@ -28,15 +28,15 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, {Label: "Receive Badly Escaped", URL: receiveBadlyEscaped, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+252999999999")}, + ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+252999999999"}, {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+2349067554729")}, + ExpectedMsgText: Sp(""), ExpectedURN: "tel:+2349067554729"}, {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC)}, + ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC)}, {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC)}, + ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC)}, {Label: "Receive invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'from' required"}, {Label: "Receive No Sender", URL: receiveNoSender, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'from' required"}, diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 4656032dc..5e8d8c8e8 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -134,11 +134,11 @@ var handleTestCases = []ChannelHandleTestCase{ URL: receiveURL, Headers: map[string]string{}, Data: helloMsg, - ExpectedURN: Sp("slack:U0123ABCDEF"), + ExpectedURN: "slack:U0123ABCDEF", ExpectedMsgText: Sp("Hello World!"), ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedExternalID: Sp("Ev0PV52K21"), + ExpectedExternalID: "Ev0PV52K21", }, { Label: "Receive image file", @@ -146,11 +146,11 @@ var handleTestCases = []ChannelHandleTestCase{ Headers: map[string]string{}, Data: imageFileMsg, ExpectedAttachments: []string{"https://files.slack.com/files-pri/T03CN5KTA6S-F03GTH43SSF/download/batata.jpg?pub_secret=39fcf577f2"}, - ExpectedURN: Sp("slack:U0123ABCDEF"), + ExpectedURN: "slack:U0123ABCDEF", ExpectedMsgText: Sp(""), ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedExternalID: Sp("Ev0PV52K21"), + ExpectedExternalID: "Ev0PV52K21", }, { Label: "Receive audio file", @@ -158,22 +158,22 @@ var handleTestCases = []ChannelHandleTestCase{ Headers: map[string]string{}, Data: audioFileMsg, ExpectedAttachments: []string{"https://files.slack.com/files-pri/T03CN5KTA6S-F03GWURCZL4/download/here_we_go_again.mp3?pub_secret=471020b300"}, - ExpectedURN: Sp("slack:U0123ABCDEF"), + ExpectedURN: "slack:U0123ABCDEF", ExpectedMsgText: Sp(""), ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedExternalID: Sp("Ev0PV52K21"), + ExpectedExternalID: "Ev0PV52K21", }, { Label: "Receive video file (not allowed)", URL: receiveURL, Headers: map[string]string{}, Data: videoFileMsg, - ExpectedURN: Sp("slack:U0123ABCDEF"), + ExpectedURN: "slack:U0123ABCDEF", ExpectedMsgText: Sp(""), ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedExternalID: Sp("Ev0PV52K21"), + ExpectedExternalID: "Ev0PV52K21", }, } diff --git a/handlers/smscentral/smscentral_test.go b/handlers/smscentral/smscentral_test.go index 3ec54b50b..32b51377d 100644 --- a/handlers/smscentral/smscentral_test.go +++ b/handlers/smscentral/smscentral_test.go @@ -9,13 +9,8 @@ import ( "github.com/nyaruka/courier/test" ) -var ( - receiveURL = "/c/sc/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive" - receiveValidMessage = "mobile=%2B2349067554729&message=Join" - invalidURN = "mobile=MTN&message=Join" - receiveNoMessage = "mobile=%2B2349067554729" - receiveNoParams = "none" - receiveNoSender = "message=Join" +const ( + receiveURL = "/c/sc/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive" ) var testChannels = []courier.Channel{ @@ -23,13 +18,45 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, - {Label: "Receive No Message", URL: receiveURL, Data: receiveNoMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+2349067554729")}, - {Label: "Receive invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Receive No Params", URL: receiveURL, Data: receiveNoParams, ExpectedStatus: 400, ExpectedResponse: "field 'mobile' required"}, - {Label: "Receive No Sender", URL: receiveURL, Data: receiveNoSender, ExpectedStatus: 400, ExpectedResponse: "field 'mobile' required"}, + { + Label: "Receive Valid Message", + URL: receiveURL, + Data: "mobile=%2B2349067554729&message=Join", + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + }, + { + Label: "Receive No Message", + URL: receiveURL, + Data: "mobile=%2B2349067554729", + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedURN: "tel:+2349067554729", + }, + { + Label: "Receive invalid URN", + URL: receiveURL, + Data: "mobile=MTN&message=Join", + ExpectedStatus: 400, + ExpectedResponse: "phone number supplied is not a number", + }, + { + Label: "Receive No Params", + URL: receiveURL, + Data: "none", + ExpectedStatus: 400, + ExpectedResponse: "field 'mobile' required", + }, + { + Label: "Receive No Sender", + URL: receiveURL, + Data: "message=Join", + ExpectedStatus: 400, + ExpectedResponse: "field 'mobile' required", + }, } func TestHandler(t *testing.T) { diff --git a/handlers/start/start_test.go b/handlers/start/start_test.go index 92b029a7c..a4e0f0b7e 100644 --- a/handlers/start/start_test.go +++ b/handlers/start/start_test.go @@ -75,13 +75,13 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("tel:+250788123123"), ExpectedDate: time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC)}, + ExpectedMsgText: Sp("Hello World"), ExpectedURN: "tel:+250788123123", ExpectedDate: time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC)}, {Label: "Receive Valid Encoded", URL: receiveURL, Data: validReceiveEncoded, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Кохання"), ExpectedURN: Sp("tel:+380501529999"), ExpectedDate: time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC)}, + ExpectedMsgText: Sp("Кохання"), ExpectedURN: "tel:+380501529999", ExpectedDate: time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC)}, {Label: "Receive Valid with empty Text", URL: receiveURL, Data: validReceiveEmptyText, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+250788123123")}, + ExpectedMsgText: Sp(""), ExpectedURN: "tel:+250788123123"}, {Label: "Receive Valid missing body", URL: receiveURL, Data: validMissingBody, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), ExpectedURN: Sp("tel:+250788123123")}, + ExpectedMsgText: Sp(""), ExpectedURN: "tel:+250788123123"}, {Label: "Receive invalidURN", URL: receiveURL, Data: invalidURNReceive, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Receive missing Request ID", URL: receiveURL, Data: missingRequestID, ExpectedStatus: 400, ExpectedResponse: "Error"}, {Label: "Receive missing From", URL: receiveURL, Data: missingFrom, ExpectedStatus: 400, ExpectedResponse: "Error"}, diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index 0bb9958cc..3ade8d0cf 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -453,38 +453,38 @@ var contactMsg = ` var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Hello World"), ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Hello World"), ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Start Message", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: startMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedChannelEvent: courier.NewConversation, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedChannelEvent: courier.NewConversation, ExpectedURN: "telegram:3527065#nicpottier", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive No Params", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: emptyMsg, ExpectedStatus: 200, ExpectedResponse: "Ignoring"}, {Label: "Receive Invalid JSON", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: "foo", ExpectedStatus: 400, ExpectedResponse: "unable to parse"}, {Label: "Receive Sticker", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: stickerMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/sticker.jpg"}, ExpectedURN: Sp("telegram:3527065"), ExpectedExternalID: Sp("44"), ExpectedDate: time.Date(2016, 1, 30, 2, 07, 48, 0, time.UTC)}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/sticker.jpg"}, ExpectedURN: "telegram:3527065", ExpectedExternalID: "44", ExpectedDate: time.Date(2016, 1, 30, 2, 07, 48, 0, time.UTC)}, {Label: "Receive Photo", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: photoMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Photo Caption"), ExpectedAttachments: []string{"/file/bota123/photo.jpg"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("85"), ExpectedDate: time.Date(2017, 5, 3, 20, 28, 38, 0, time.UTC)}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Photo Caption"), ExpectedAttachments: []string{"/file/bota123/photo.jpg"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "85", ExpectedDate: time.Date(2017, 5, 3, 20, 28, 38, 0, time.UTC)}, {Label: "Receive Video", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: videoMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/video.jpg"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("86"), ExpectedDate: time.Date(2017, 5, 3, 20, 29, 24, 0, time.UTC)}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/video.jpg"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "86", ExpectedDate: time.Date(2017, 5, 3, 20, 29, 24, 0, time.UTC)}, {Label: "Receive Voice", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: voiceMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/voice.mp4"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("91"), ExpectedDate: time.Date(2017, 5, 3, 20, 50, 46, 0, time.UTC)}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/voice.mp4"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "91", ExpectedDate: time.Date(2017, 5, 3, 20, 50, 46, 0, time.UTC)}, {Label: "Receive Document", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: documentMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/document.xls"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("92"), ExpectedDate: time.Date(2017, 5, 3, 20, 58, 20, 0, time.UTC)}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/document.xls"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "92", ExpectedDate: time.Date(2017, 5, 3, 20, 58, 20, 0, time.UTC)}, {Label: "Receive Location", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: locationMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("-2.890287,-79.004333"), ExpectedAttachments: []string{"geo:-2.890287,-79.004333"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("94"), ExpectedDate: time.Date(2017, 5, 3, 21, 00, 44, 0, time.UTC)}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("-2.890287,-79.004333"), ExpectedAttachments: []string{"geo:-2.890287,-79.004333"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "94", ExpectedDate: time.Date(2017, 5, 3, 21, 00, 44, 0, time.UTC)}, {Label: "Receive Venue", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: venueMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Cuenca, Provincia del Azuay"), ExpectedAttachments: []string{"geo:-2.898944,-79.006835"}, ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("95"), ExpectedDate: time.Date(2017, 5, 3, 21, 05, 20, 0, time.UTC)}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Cuenca, Provincia del Azuay"), ExpectedAttachments: []string{"geo:-2.898944,-79.006835"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "95", ExpectedDate: time.Date(2017, 5, 3, 21, 05, 20, 0, time.UTC)}, {Label: "Receive Contact", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: contactMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Adolf Taxi (0788531373)"), ExpectedURN: Sp("telegram:3527065#nicpottier"), ExpectedExternalID: Sp("96"), ExpectedDate: time.Date(2017, 5, 3, 21, 9, 15, 0, time.UTC)}, + ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Adolf Taxi (0788531373)"), ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "96", ExpectedDate: time.Date(2017, 5, 3, 21, 9, 15, 0, time.UTC)}, {Label: "Receive Empty", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: emptyMsg, ExpectedStatus: 200, ExpectedResponse: "Ignoring"}, diff --git a/handlers/telesom/telesom_test.go b/handlers/telesom/telesom_test.go index c322ae7a6..c377032bf 100644 --- a/handlers/telesom/telesom_test.go +++ b/handlers/telesom/telesom_test.go @@ -24,13 +24,13 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, {Label: "Invalid URN", URL: invalidURN, Data: "", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Receive No Params", URL: receiveNoParams, Data: "", ExpectedStatus: 400, ExpectedResponse: "field 'mobile' required"}, {Label: "Receive No Sender", URL: receiveNoSender, Data: "", ExpectedStatus: 400, ExpectedResponse: "field 'mobile' required"}, {Label: "Receive Valid Message", URL: receiveNoParams, Data: "mobile=%2B2349067554729&msg=Join", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, {Label: "Invalid URN", URL: receiveNoParams, Data: "mobile=MTN&msg=Join", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'mobile' required"}, {Label: "Receive No Sender", URL: receiveNoParams, Data: "msg=Join", ExpectedStatus: 400, ExpectedResponse: "field 'mobile' required"}, diff --git a/handlers/test.go b/handlers/test.go index 110f5bddd..a66552164 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -41,12 +41,12 @@ type ChannelHandleTestCase struct { ExpectedContactName *string ExpectedMsgText *string - ExpectedURN *string - ExpectedURNAuth *string + ExpectedURN urns.URN + ExpectedURNAuth string ExpectedAttachments []string ExpectedDate time.Time ExpectedMsgStatus courier.MsgStatusValue - ExpectedExternalID *string + ExpectedExternalID string ExpectedMsgID int64 ExpectedChannelEvent courier.ChannelEventType @@ -378,27 +378,29 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri if tc.ExpectedChannelEventExtra != nil { require.Equal(tc.ExpectedChannelEventExtra, event.Extra()) } - if tc.ExpectedURN != nil { + if tc.ExpectedURN != "" { if msg != nil { - require.Equal(*tc.ExpectedURN, string(msg.URN())) + assert.Equal(t, tc.ExpectedURN, msg.URN()) } else if event != nil { - require.Equal(*tc.ExpectedURN, string(event.URN())) + assert.Equal(t, tc.ExpectedURN, event.URN()) } else { - require.Equal(*tc.ExpectedURN, "") + assert.Equal(t, tc.ExpectedURN, "") } } - if tc.ExpectedURNAuth != nil { + if tc.ExpectedURNAuth != "" { if msg != nil { - require.Equal(*tc.ExpectedURNAuth, msg.URNAuth()) + assert.Equal(t, tc.ExpectedURNAuth, msg.URNAuth()) + } else { + assert.Equal(t, tc.ExpectedURNAuth, "") } } - if tc.ExpectedExternalID != nil { + if tc.ExpectedExternalID != "" { if msg != nil { - require.Equal(*tc.ExpectedExternalID, msg.ExternalID()) + assert.Equal(t, tc.ExpectedExternalID, msg.ExternalID()) } else if status != nil { - require.Equal(*tc.ExpectedExternalID, status.ExternalID()) + assert.Equal(t, tc.ExpectedExternalID, status.ExternalID()) } else { - require.Equal(*tc.ExpectedExternalID, "") + assert.Equal(t, tc.ExpectedExternalID, "") } } if tc.ExpectedMsgStatus != "" { diff --git a/handlers/thinq/thinq_test.go b/handlers/thinq/thinq_test.go index ea5fdf923..92cfe031f 100644 --- a/handlers/thinq/thinq_test.go +++ b/handlers/thinq/thinq_test.go @@ -13,31 +13,62 @@ var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TQ", "+12065551212", "US", nil), } -var ( +const ( receiveURL = "/c/tq/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" - - receiveValid = "message=hello+world&from=2065551234&type=sms&to=2065551212" - receiveMedia = "message=http://foo.bar/foo.png&hello+world&from=2065551234&type=mms&to=2065551212" - - statusURL = "/c/tq/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/" - statusValid = "guid=1234&status=DELIVRD" - statusInvalid = "guid=1234&status=UN" - missingGUID = "status=DELIVRD" + statusURL = "/c/tq/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/" ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: receiveValid, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("tel:+12065551234")}, - {Label: "Receive No Params", URL: receiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: `'From' failed on the 'required'`}, - {Label: "Receive Media", URL: receiveURL, Data: receiveMedia, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedURN: Sp("tel:+12065551234"), ExpectedAttachments: []string{"http://foo.bar/foo.png"}}, + { + Label: "Receive Valid", + URL: receiveURL, + Data: "message=hello+world&from=2065551234&type=sms&to=2065551212", + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedMsgText: Sp("hello world"), + ExpectedURN: "tel:+12065551234", + }, + { + Label: "Receive No Params", + URL: receiveURL, + Data: " ", + ExpectedStatus: 400, + ExpectedResponse: `'From' failed on the 'required'`, + }, + { + Label: "Receive Media", + URL: receiveURL, + Data: "message=http://foo.bar/foo.png&hello+world&from=2065551234&type=mms&to=2065551212", + ExpectedStatus: 200, + ExpectedResponse: "Accepted", + ExpectedURN: "tel:+12065551234", + ExpectedAttachments: []string{"http://foo.bar/foo.png"}, + }, - {Label: "Status Valid", URL: statusURL, Data: statusValid, ExpectedStatus: 200, - ExpectedExternalID: Sp("1234"), ExpectedResponse: `"status":"D"`}, - {Label: "Status Invalid", URL: statusURL, Data: statusInvalid, ExpectedStatus: 400, - ExpectedExternalID: Sp("1234"), ExpectedResponse: `"unknown status: 'UN'"`}, - {Label: "Status Missing GUID", URL: statusURL, Data: missingGUID, ExpectedStatus: 400, - ExpectedExternalID: Sp("1234"), ExpectedResponse: `'GUID' failed on the 'required' tag`}, + { + Label: "Status Valid", + URL: statusURL, + Data: "guid=1234&status=DELIVRD", + ExpectedStatus: 200, + ExpectedExternalID: "1234", + ExpectedResponse: `"status":"D"`, + }, + { + Label: "Status Invalid", + URL: statusURL, + Data: "guid=1234&status=UN", + ExpectedStatus: 400, + ExpectedExternalID: "1234", + ExpectedResponse: `"unknown status: 'UN'"`, + }, + { + Label: "Status Missing GUID", + URL: statusURL, + Data: "status=DELIVRD", + ExpectedStatus: 400, + ExpectedExternalID: "1234", + ExpectedResponse: `'GUID' failed on the 'required' tag`, + }, } func TestHandler(t *testing.T) { diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index d0089d9ff..d94be3518 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -77,10 +77,10 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveURL, Data: receiveValid, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, {Label: "Receive Button Ignored", URL: receiveURL, Data: receiveButtonIgnored, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, {Label: "Receive Invalid Signature", URL: receiveURL, Data: receiveValid, ExpectedStatus: 400, ExpectedResponse: "invalid request signature", PrepRequest: addInvalidSignature}, @@ -88,13 +88,13 @@ var testCases = []ChannelHandleTestCase{ {Label: "Receive No Params", URL: receiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: "field 'messagesid' required", PrepRequest: addValidSignature}, {Label: "Receive Media", URL: receiveURL, Data: receiveMedia, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, + ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, {Label: "Receive Media With Msg", URL: receiveURL, Data: receiveMediaWithMsg, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, + ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, {Label: "Receive Base64", URL: receiveURL, Data: receiveBase64, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, {Label: "Status Stop contact", URL: statusURL, Data: statusStop, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, PrepRequest: addValidSignature}, @@ -102,22 +102,22 @@ var testCases = []ChannelHandleTestCase{ PrepRequest: addValidSignature}, {Label: "Status Invalid Status", URL: statusURL, Data: statusInvalid, ExpectedStatus: 400, ExpectedResponse: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: statusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status Valid", URL: statusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status Read", URL: statusURL, Data: statusRead, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status Read", URL: statusURL, Data: statusRead, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, {Label: "Status ID Valid", URL: statusIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: statusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status ID Invalid", URL: statusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } var tmsTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: tmsReceiveURL, Data: receiveValid, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, {Label: "Receive TMS extra", URL: tmsReceiveURL, Data: tmsReceiveExtra, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("John Cruz"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMbbf29aeb9d380ce2a1c0ae4635ff9dab"), + ExpectedMsgText: Sp("John Cruz"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMbbf29aeb9d380ce2a1c0ae4635ff9dab", PrepRequest: addValidSignature}, {Label: "Receive Invalid Signature", URL: tmsReceiveURL, Data: receiveValid, ExpectedStatus: 400, ExpectedResponse: "invalid request signature", PrepRequest: addInvalidSignature}, @@ -125,38 +125,38 @@ var tmsTestCases = []ChannelHandleTestCase{ {Label: "Receive No Params", URL: tmsReceiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: "field 'messagesid' required", PrepRequest: addValidSignature}, {Label: "Receive Media", URL: tmsReceiveURL, Data: receiveMedia, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, + ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, {Label: "Receive Media With Msg", URL: tmsReceiveURL, Data: receiveMediaWithMsg, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, + ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, {Label: "Receive Base64", URL: tmsReceiveURL, Data: receiveBase64, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, {Label: "Status Stop contact", URL: tmsStatusURL, Data: statusStop, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, PrepRequest: addValidSignature}, {Label: "Status TMS extra", URL: tmsStatusURL, Data: tmsStatusExtra, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`, - ExpectedExternalID: Sp("SM0b6e2697aae04182a9f5b5c7a8994c7f"), PrepRequest: addValidSignature}, + ExpectedExternalID: "SM0b6e2697aae04182a9f5b5c7a8994c7f", PrepRequest: addValidSignature}, {Label: "Status No Params", URL: tmsStatusURL, Data: " ", ExpectedStatus: 200, ExpectedResponse: "no msg status, ignoring", PrepRequest: addValidSignature}, {Label: "Status Invalid Status", URL: tmsStatusURL, Data: statusInvalid, ExpectedStatus: 400, ExpectedResponse: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: tmsStatusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status Valid", URL: tmsStatusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, {Label: "Status ID Valid", URL: tmsStatusIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: tmsStatusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status ID Invalid", URL: tmsStatusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } var twTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: twReceiveURL, Data: receiveValid, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, {Label: "Receive Forwarded Valid", URL: twReceiveURL, Data: receiveValid, Headers: map[string]string{forwardedPathHeader: "/handlers/twilio/receive/8eb23e93-5ecb-45ba-b726-3b064e0c56ab"}, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addForwardSignature}, {Label: "Receive Invalid Signature", URL: twReceiveURL, Data: receiveValid, ExpectedStatus: 400, ExpectedResponse: "invalid request signature", PrepRequest: addInvalidSignature}, @@ -164,13 +164,13 @@ var twTestCases = []ChannelHandleTestCase{ {Label: "Receive No Params", URL: twReceiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: "field 'messagesid' required", PrepRequest: addValidSignature}, {Label: "Receive Media", URL: twReceiveURL, Data: receiveMedia, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, + ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, {Label: "Receive Media With Msg", URL: twReceiveURL, Data: receiveMediaWithMsg, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, + ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, {Label: "Receive Base64", URL: twReceiveURL, Data: receiveBase64, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, {Label: "Status Stop contact", URL: twStatusURL, Data: statusStop, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, PrepRequest: addValidSignature}, @@ -178,58 +178,58 @@ var twTestCases = []ChannelHandleTestCase{ PrepRequest: addValidSignature}, {Label: "Status Invalid Status", URL: twStatusURL, Data: statusInvalid, ExpectedStatus: 400, ExpectedResponse: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: twStatusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status Valid", URL: twStatusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, {Label: "Status ID Valid", URL: twStatusIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: twStatusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status ID Invalid", URL: twStatusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } var swTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: swReceiveURL, Data: receiveValid, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b")}, + ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, {Label: "Receive No Params", URL: swReceiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: "field 'messagesid' required"}, {Label: "Receive Media", URL: swReceiveURL, Data: receiveMedia, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}}, + ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}}, {Label: "Receive Media With Msg", URL: swReceiveURL, Data: receiveMediaWithMsg, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}}, + ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}}, {Label: "Receive Base64", URL: swReceiveURL, Data: receiveBase64, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: Sp("tel:+14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b")}, + ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, {Label: "Status Stop contact", URL: swStatusURL, Data: statusStop, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, PrepRequest: addValidSignature}, {Label: "Status No Params", URL: swStatusURL, Data: " ", ExpectedStatus: 200, ExpectedResponse: "no msg status, ignoring"}, {Label: "Status Invalid Status", URL: swStatusURL, Data: statusInvalid, ExpectedStatus: 400, ExpectedResponse: "unknown status 'huh'"}, - {Label: "Status Valid", URL: swStatusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b")}, + {Label: "Status Valid", URL: swStatusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, {Label: "Status ID Valid", URL: swStatusIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedMsgID: 12345}, - {Label: "Status ID Invalid", URL: swStatusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b")}, + {Label: "Status ID Invalid", URL: swStatusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, } var waTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveURL, Data: waReceiveValid, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("whatsapp:14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + ExpectedMsgText: Sp("Msg"), ExpectedURN: "whatsapp:14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } var twaTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: twaReceiveURL, Data: waReceiveValid, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("whatsapp:14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + ExpectedMsgText: Sp("Msg"), ExpectedURN: "whatsapp:14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, {Label: "Receive Valid", URL: twaReceiveURL, Data: waReceiveButtonValid, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Confirm"), ExpectedURN: Sp("whatsapp:14133881111"), ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + ExpectedMsgText: Sp("Confirm"), ExpectedURN: "whatsapp:14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, {Label: "Receive Prefixless URN", URL: twaReceiveURL, Data: waReceivePrefixlessURN, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("whatsapp:14133881111"), ExpectedExternalID: Sp("SM681a1f26d9ec591431ce406e8f399525"), + ExpectedMsgText: Sp("Msg"), ExpectedURN: "whatsapp:14133881111", ExpectedExternalID: "SM681a1f26d9ec591431ce406e8f399525", PrepRequest: addValidSignature}, {Label: "Status No Params", URL: twaStatusURL, Data: " ", ExpectedStatus: 200, ExpectedResponse: "no msg status, ignoring", PrepRequest: addValidSignature}, {Label: "Status Invalid Status", URL: twaStatusURL, Data: statusInvalid, ExpectedStatus: 400, ExpectedResponse: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: twaStatusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status Valid", URL: twaStatusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, {Label: "Status ID Valid", URL: twaStatusIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: twaStatusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: Sp("SMe287d7109a5a925f182f0e07fe5b223b"), + {Label: "Status ID Invalid", URL: twaStatusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } diff --git a/handlers/twitter/twitter_test.go b/handlers/twitter/twitter_test.go index 5c0edd989..eea5ef134 100644 --- a/handlers/twitter/twitter_test.go +++ b/handlers/twitter/twitter_test.go @@ -168,10 +168,10 @@ var notJSON = `blargh` var testCases = []ChannelHandleTestCase{ {Label: "Receive Message", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nicolas Pottier"), ExpectedURN: Sp("twitterid:272953809#nicpottier"), - ExpectedMsgText: Sp("Hello World & good wishes."), ExpectedExternalID: Sp("958501034212564996"), ExpectedDate: time.Date(2018, 1, 31, 0, 43, 49, 301000000, time.UTC)}, + ExpectedContactName: Sp("Nicolas Pottier"), ExpectedURN: "twitterid:272953809#nicpottier", + ExpectedMsgText: Sp("Hello World & good wishes."), ExpectedExternalID: "958501034212564996", ExpectedDate: time.Date(2018, 1, 31, 0, 43, 49, 301000000, time.UTC)}, {Label: "Receive Attachment", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: attachment, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Hello"), ExpectedAttachments: []string{"https://image.foo.com/image.jpg"}, ExpectedURN: Sp("twitterid:272953809#nicpottier"), ExpectedExternalID: Sp("958501034212564996"), ExpectedDate: time.Date(2018, 1, 31, 0, 43, 49, 301000000, time.UTC)}, + ExpectedMsgText: Sp("Hello"), ExpectedAttachments: []string{"https://image.foo.com/image.jpg"}, ExpectedURN: "twitterid:272953809#nicpottier", ExpectedExternalID: "958501034212564996", ExpectedDate: time.Date(2018, 1, 31, 0, 43, 49, 301000000, time.UTC)}, {Label: "Not JSON", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "Error"}, {Label: "Invalid Twitter handle", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidTwitterHandle, ExpectedStatus: 400, ExpectedResponse: "invalid twitter handle"}, {Label: "Invalid Twitter ID", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidTwitterID, ExpectedStatus: 400, ExpectedResponse: "invalid twitter id"}, diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index 407beab63..500719c0b 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -482,7 +482,7 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("incoming msg"), ExpectedURN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExpectedExternalID: Sp("4987381189870374000"), + ExpectedMsgText: Sp("incoming msg"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", PrepRequest: addValidSignature}, {Label: "Receive invalid signature", URL: receiveURL, Data: validMsg, ExpectedStatus: 400, ExpectedResponse: "invalid request signature", PrepRequest: addInvalidSignature}, @@ -507,23 +507,23 @@ var testCases = []ChannelHandleTestCase{ {Label: "Video missing media", URL: receiveURL, Data: rejectedVideo, ExpectedStatus: 400, ExpectedResponse: "missing text or media in message in request body", PrepRequest: addValidSignature}, {Label: "Valid Contact receive", URL: receiveURL, Data: validReceiveContact, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Alex: +12067799191"), ExpectedURN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExpectedExternalID: Sp("4987381189870374000"), + ExpectedMsgText: Sp("Alex: +12067799191"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", PrepRequest: addValidSignature}, {Label: "Valid URL receive", URL: receiveURL, Data: validReceiveURL, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("http://foo.com/"), ExpectedURN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExpectedExternalID: Sp("4987381189870374000"), + ExpectedMsgText: Sp("http://foo.com/"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", PrepRequest: addValidSignature}, {Label: "Valid Location receive", URL: receiveURL, Data: validReceiveLocation, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("incoming msg"), ExpectedURN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExpectedExternalID: Sp("4987381189870374000"), + ExpectedMsgText: Sp("incoming msg"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, PrepRequest: addValidSignature}, {Label: "Valid Sticker", URL: receiveURL, Data: validSticker, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("incoming msg"), ExpectedURN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExpectedExternalID: Sp("4987381189870374000"), + ExpectedMsgText: Sp("incoming msg"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", ExpectedAttachments: []string{"https://viber.github.io/docs/img/stickers/40133.png"}, PrepRequest: addValidSignature}, } var testWelcomeMessageCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("incoming msg"), ExpectedURN: Sp("viber:xy5/5y6O81+/kbWHpLhBoA=="), ExpectedExternalID: Sp("4987381189870374000"), + ExpectedMsgText: Sp("incoming msg"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", PrepRequest: addValidSignature}, {Label: "Conversation Started", URL: receiveURL, Data: validConversationStarted, ExpectedStatus: 200, ExpectedResponse: `{"auth_token":"Token","text":"Welcome to VP, Please subscribe here for more.","type":"text","tracking_data":"0"}`, PrepRequest: addValidSignature}, } diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index 9393c5350..ebb795be0 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -236,8 +236,8 @@ var testCases = []ChannelHandleTestCase{ Data: msgHelloWorld, ExpectedStatus: 200, ExpectedResponse: "ok", - ExpectedURN: Sp("vk:123456"), - ExpectedExternalID: Sp("1"), + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), }, { @@ -246,8 +246,8 @@ var testCases = []ChannelHandleTestCase{ Data: msgEmpty, ExpectedStatus: 400, ExpectedResponse: "no text or attachment", - ExpectedURN: Sp("vk:123456"), - ExpectedExternalID: Sp("1"), + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), }, { @@ -256,8 +256,8 @@ var testCases = []ChannelHandleTestCase{ Data: msgFirstPhotoAttachment, ExpectedStatus: 200, ExpectedResponse: "ok", - ExpectedURN: Sp("vk:123456"), - ExpectedExternalID: Sp("1"), + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), ExpectedAttachments: []string{"https://foo.bar/x-photo.jpg"}, }, @@ -267,8 +267,8 @@ var testCases = []ChannelHandleTestCase{ Data: msgFirstGraffitiAttachment, ExpectedStatus: 200, ExpectedResponse: "ok", - ExpectedURN: Sp("vk:123456"), - ExpectedExternalID: Sp("1"), + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), ExpectedAttachments: []string{"https://foo.bar/graffiti.png"}, }, @@ -278,8 +278,8 @@ var testCases = []ChannelHandleTestCase{ Data: msgFirstStickerAttachment, ExpectedStatus: 200, ExpectedResponse: "ok", - ExpectedURN: Sp("vk:123456"), - ExpectedExternalID: Sp("1"), + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), ExpectedAttachments: []string{"https://foo.bar/128x128_sticker.png"}, }, @@ -289,8 +289,8 @@ var testCases = []ChannelHandleTestCase{ Data: msgFirstAudioAttachment, ExpectedStatus: 200, ExpectedResponse: "ok", - ExpectedURN: Sp("vk:123456"), - ExpectedExternalID: Sp("1"), + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), ExpectedAttachments: []string{"https://foo.bar/audio.mp3"}, }, @@ -300,8 +300,8 @@ var testCases = []ChannelHandleTestCase{ Data: msgFirstDocAttachment, ExpectedStatus: 200, ExpectedResponse: "ok", - ExpectedURN: Sp("vk:123456"), - ExpectedExternalID: Sp("1"), + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), ExpectedAttachments: []string{"https://foo.bar/doc.pdf"}, }, @@ -311,8 +311,8 @@ var testCases = []ChannelHandleTestCase{ Data: msgKeyboard, ExpectedStatus: 200, ExpectedResponse: "ok", - ExpectedURN: Sp("vk:123456"), - ExpectedExternalID: Sp("1"), + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), }, { @@ -321,8 +321,8 @@ var testCases = []ChannelHandleTestCase{ Data: msgGeolocationOnly, ExpectedStatus: 200, ExpectedResponse: "ok", - ExpectedURN: Sp("vk:123456"), - ExpectedExternalID: Sp("1"), + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), ExpectedAttachments: []string{"geo:-9.652278,-35.701095"}, }, diff --git a/handlers/wavy/wavy_test.go b/handlers/wavy/wavy_test.go index 36535f78d..ade4f3de1 100644 --- a/handlers/wavy/wavy_test.go +++ b/handlers/wavy/wavy_test.go @@ -80,7 +80,7 @@ var ( var testCases = []ChannelHandleTestCase{ {Label: "Receive Message", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Eu quero pizza"), ExpectedURN: Sp("tel:+5516981562820"), ExpectedExternalID: Sp("external_id"), ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)}, + ExpectedMsgText: Sp("Eu quero pizza"), ExpectedURN: "tel:+5516981562820", ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)}, {Label: "Invalid JSON receive", URL: receiveURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, {Label: "Missing Keys receive", URL: receiveURL, Data: missingRequiredKeys, ExpectedStatus: 400, ExpectedResponse: "validation for 'ID' failed on the 'required'"}, diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index 7e6d992be..d42f8f59a 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -144,19 +144,19 @@ func addInvalidSignature(r *http.Request) { var testCases = []ChannelHandleTestCase{ {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp("Simple Message"), ExpectedURN: Sp("wechat:1234"), ExpectedExternalID: Sp("123456"), + ExpectedMsgText: Sp("Simple Message"), ExpectedURN: "wechat:1234", ExpectedExternalID: "123456", ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, {Label: "Missing params", URL: receiveURL, Data: missingParamsRequired, ExpectedStatus: 400, ExpectedResponse: "Error:Field validation"}, {Label: "Missing params Event or MsgId", URL: receiveURL, Data: missingParams, ExpectedStatus: 400, ExpectedResponse: "missing parameters, must have either 'MsgId' or 'Event'"}, {Label: "Receive Image", URL: receiveURL, Data: imageMessage, ExpectedStatus: 200, ExpectedResponse: "", - ExpectedMsgText: Sp(""), ExpectedURN: Sp("wechat:1234"), ExpectedExternalID: Sp("123456"), + ExpectedMsgText: Sp(""), ExpectedURN: "wechat:1234", ExpectedExternalID: "123456", ExpectedAttachments: []string{"https://api.weixin.qq.com/cgi-bin/media/get?media_id=12"}, ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedStatus: 200, ExpectedResponse: "Event Accepted", - ExpectedChannelEvent: courier.NewConversation, ExpectedURN: Sp("wechat:1234")}, + ExpectedChannelEvent: courier.NewConversation, ExpectedURN: "wechat:1234"}, {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, ExpectedStatus: 200, ExpectedResponse: "unknown event"}, diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index fee7fd879..53b135104 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -293,33 +293,33 @@ var ( var waTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: waReceiveURL, Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedContactName: Sp("Jerry Cooney"), ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, + ExpectedContactName: Sp("Jerry Cooney"), ExpectedMsgText: Sp("hello world"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Duplicate Valid Message", URL: waReceiveURL, Data: duplicateMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp("hello world"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, + ExpectedMsgText: Sp("hello world"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Audio Message", URL: waReceiveURL, Data: audioMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Button Message", URL: waReceiveURL, Data: buttonMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp("BUTTON1"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, + ExpectedMsgText: Sp("BUTTON1"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Document Message", URL: waReceiveURL, Data: documentMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp("the caption"), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, + ExpectedMsgText: Sp("the caption"), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Image Message", URL: waReceiveURL, Data: imageMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp("the caption"), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, + ExpectedMsgText: Sp("the caption"), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Interactive Button Message", URL: waReceiveURL, Data: interactiveButtonMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp("BUTTON1"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, + ExpectedMsgText: Sp("BUTTON1"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Interactive List Message", URL: waReceiveURL, Data: interactiveListMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp("ROW1"), ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, + ExpectedMsgText: Sp("ROW1"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Location Message", URL: waReceiveURL, Data: locationMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Video Message", URL: waReceiveURL, Data: videoMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Voice Message", URL: waReceiveURL, Data: voiceMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:250788123123"), ExpectedExternalID: Sp("41"), ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: invalidMsg, ExpectedStatus: 400, ExpectedResponse: "unable to parse"}, {Label: "Receive Invalid From", URL: waReceiveURL, Data: invalidFrom, ExpectedStatus: 400, ExpectedResponse: "invalid whatsapp id"}, {Label: "Receive Invalid Timestamp", URL: waReceiveURL, Data: invalidTimestamp, ExpectedStatus: 400, ExpectedResponse: "invalid timestamp"}, {Label: "Receive Valid Status", URL: waReceiveURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `"type":"status"`, - ExpectedMsgStatus: "S", ExpectedExternalID: Sp("9712A34B4A8B6AD50F")}, + ExpectedMsgStatus: "S", ExpectedExternalID: "9712A34B4A8B6AD50F"}, {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: "not json", ExpectedStatus: 400, ExpectedResponse: "unable to parse"}, {Label: "Receive Invalid Status", URL: waReceiveURL, Data: invalidStatus, ExpectedStatus: 400, ExpectedResponse: `"unknown status: in_orbit"`}, {Label: "Receive Ignore Status", URL: waReceiveURL, Data: ignoreStatus, ExpectedStatus: 200, ExpectedResponse: `"ignoring status: deleted"`}, diff --git a/handlers/yo/yo_test.go b/handlers/yo/yo_test.go index bdd351a58..f91299712 100644 --- a/handlers/yo/yo_test.go +++ b/handlers/yo/yo_test.go @@ -27,13 +27,13 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, {Label: "Receive Valid From", URL: receiveValidMessageFrom, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729")}, + ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC)}, + ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC)}, {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: Sp("tel:+2349067554729"), ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC)}, + ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC)}, {Label: "Invalid URN", URL: receiveInvalidURN, Data: "", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Receive No Params", URL: receiveNoParams, Data: "", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from'"}, {Label: "Receive No Sender", URL: receiveNoSender, Data: "", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from'"}, diff --git a/handlers/zenvia/zenvia_test.go b/handlers/zenvia/zenvia_test.go index 62a75a956..ef32b3ddb 100644 --- a/handlers/zenvia/zenvia_test.go +++ b/handlers/zenvia/zenvia_test.go @@ -197,13 +197,13 @@ var missingFieldsReceive = `{ var testWhatappCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveWhatsappURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, + ExpectedMsgText: Sp("Msg"), ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, {Label: "Receive file Valid", URL: receiveWhatsappURL, Data: fileReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, {Label: "Receive location Valid", URL: receiveWhatsappURL, Data: locationReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, {Label: "Not JSON body", URL: receiveWhatsappURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, {Label: "Wrong JSON schema", URL: receiveWhatsappURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, @@ -218,13 +218,13 @@ var testWhatappCases = []ChannelHandleTestCase{ var testSMSCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveSMSURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, + ExpectedMsgText: Sp("Msg"), ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, {Label: "Receive file Valid", URL: receiveSMSURL, Data: fileReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, {Label: "Receive location Valid", URL: receiveSMSURL, Data: locationReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: Sp("whatsapp:254791541111"), ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, + ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, {Label: "Not JSON body", URL: receiveSMSURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, {Label: "Wrong JSON schema", URL: receiveSMSURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, diff --git a/handlers/zenviaold/zenviaold_test.go b/handlers/zenviaold/zenviaold_test.go index 34a459da6..1f7f46ff0 100644 --- a/handlers/zenviaold/zenviaold_test.go +++ b/handlers/zenviaold/zenviaold_test.go @@ -106,7 +106,7 @@ var missingFieldsReceive = `{ var testCases = []ChannelHandleTestCase{ {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), ExpectedURN: Sp("tel:+254791541111"), ExpectedDate: time.Date(2017, 5, 3, 06, 04, 45, 123000000, time.UTC)}, + ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+254791541111", ExpectedDate: time.Date(2017, 5, 3, 06, 04, 45, 123000000, time.UTC)}, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, {Label: "Not JSON body", URL: receiveURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, From 574f8105c2a0b141d766729f6aacaafb3107c93b Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 29 Aug 2022 14:23:24 -0500 Subject: [PATCH 120/294] Rename test struct fields for clarity --- .../africastalking/africastalking_test.go | 98 +-- handlers/arabiacell/arabiacell_test.go | 32 +- handlers/blackmyna/blackmyna_test.go | 70 +- handlers/bongolive/bongolive_test.go | 88 +-- handlers/burstsms/burstsms_test.go | 40 +- handlers/chikka/chikka_test.go | 96 +-- handlers/clickatell/clickatell_test.go | 102 +-- handlers/clickmobile/clickmobile_test.go | 74 +- handlers/clicksend/clicksend_test.go | 38 +- handlers/dart/dart_test.go | 98 +-- handlers/discord/discord_test.go | 62 +- handlers/dmark/dmark_test.go | 92 +-- handlers/external/external_test.go | 358 ++++----- handlers/facebook/facebook_test.go | 272 +++---- handlers/facebookapp/facebookapp_test.go | 686 +++++++++--------- handlers/firebase/firebase_test.go | 58 +- handlers/freshchat/freshchat_test.go | 66 +- handlers/globe/globe_test.go | 74 +- .../highconnection/highconnection_test.go | 56 +- handlers/hormuud/hormuud_test.go | 22 +- handlers/i2sms/i2sms_test.go | 32 +- handlers/infobip/infobip_test.go | 36 +- handlers/jasmin/jasmin_test.go | 44 +- handlers/jiochat/jiochat_test.go | 34 +- handlers/junebug/junebug_test.go | 42 +- handlers/kaleyra/kaleyra_test.go | 72 +- handlers/kannel/kannel_test.go | 56 +- handlers/line/line_test.go | 50 +- handlers/m3tech/m3tech_test.go | 54 +- handlers/macrokiosk/macrokiosk_test.go | 30 +- handlers/mblox/mblox_test.go | 22 +- handlers/messangi/messangi_test.go | 34 +- handlers/mtarget/mtarget_test.go | 32 +- handlers/nexmo/nexmo_test.go | 38 +- handlers/novo/novo_test.go | 48 +- handlers/playmobile/playmobile_test.go | 78 +- handlers/plivo/plivo_test.go | 26 +- handlers/redrabbit/redrabbit_test.go | 32 +- handlers/rocketchat/rocketchat_test.go | 32 +- handlers/shaqodoon/shaqodoon_test.go | 34 +- handlers/slack/slack_test.go | 36 +- handlers/smscentral/smscentral_test.go | 74 +- handlers/start/start_test.go | 30 +- handlers/telegram/telegram_test.go | 74 +- handlers/telesom/telesom_test.go | 32 +- handlers/test.go | 60 +- handlers/thinq/thinq_test.go | 50 +- handlers/twiml/twiml_test.go | 190 ++--- handlers/twitter/twitter_test.go | 30 +- handlers/viber/viber_test.go | 74 +- handlers/vk/vk_test.go | 74 +- handlers/wavy/wavy_test.go | 34 +- handlers/wechat/wechat_test.go | 32 +- handlers/whatsapp/whatsapp_test.go | 100 +-- handlers/yo/yo_test.go | 40 +- handlers/zenvia/zenvia_test.go | 64 +- handlers/zenviaold/zenviaold_test.go | 36 +- 57 files changed, 2166 insertions(+), 2172 deletions(-) diff --git a/handlers/africastalking/africastalking_test.go b/handlers/africastalking/africastalking_test.go index 1d64b9999..4fb75f44e 100644 --- a/handlers/africastalking/africastalking_test.go +++ b/handlers/africastalking/africastalking_test.go @@ -24,8 +24,8 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive Valid", URL: receiveURL, Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=%2B254791541111", - ExpectedStatus: 200, - ExpectedResponse: "Message Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Message Accepted", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+254791541111", ExpectedExternalID: "ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3", @@ -35,68 +35,68 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive Valid", URL: receiveURL, Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03+06%3A04%3A45&from=%2B254791541111", - ExpectedStatus: 200, - ExpectedResponse: "Message Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Message Accepted", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+254791541111", ExpectedExternalID: "ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3", ExpectedDate: time.Date(2017, 5, 3, 06, 04, 45, 0, time.UTC), }, { - Label: "Receive Empty", - URL: receiveURL, - Data: "empty", - ExpectedStatus: 400, - ExpectedResponse: "field 'id' required", + Label: "Receive Empty", + URL: receiveURL, + Data: "empty", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'id' required", }, { - Label: "Receive Missing Text", - URL: receiveURL, - Data: "linkId=03090445075804249226&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=%2B254791541111", - ExpectedStatus: 400, - ExpectedResponse: "field 'text' required", + Label: "Receive Missing Text", + URL: receiveURL, + Data: "linkId=03090445075804249226&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=%2B254791541111", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'text' required", }, { - Label: "Invalid URN", - URL: receiveURL, - Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=MTN", - ExpectedStatus: 400, - ExpectedResponse: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL, + Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=MTN", + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", }, { - Label: "Invalid Date", - URL: receiveURL, - Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04&from=%2B254791541111", - ExpectedStatus: 400, - ExpectedResponse: "invalid date format", + Label: "Invalid Date", + URL: receiveURL, + Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04&from=%2B254791541111", + ExpectedRespStatus: 400, + ExpectedRespBody: "invalid date format", }, { - Label: "Status Invalid", - URL: statusURL, - ExpectedStatus: 400, - Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Borked", - ExpectedResponse: "unknown status", + Label: "Status Invalid", + URL: statusURL, + Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Borked", + ExpectedRespStatus: 400, + ExpectedRespBody: "unknown status", }, { - Label: "Status Missing", - URL: statusURL, - ExpectedStatus: 400, - Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7", - ExpectedResponse: "field 'status' required", + Label: "Status Missing", + URL: statusURL, + Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'status' required", }, { - Label: "Status Success", - URL: statusURL, - ExpectedStatus: 200, - Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Success", - ExpectedResponse: `"status":"D"`, + Label: "Status Success", + URL: statusURL, + Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Success", + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"D"`, }, { - Label: "Status Expired", - URL: statusURL, - ExpectedStatus: 200, - Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Expired", - ExpectedResponse: `"status":"F"`, + Label: "Status Expired", + URL: statusURL, + Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Expired", + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"F"`, }, } @@ -122,7 +122,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"apikey": "KEY"}, ExpectedPostParams: map[string]string{"message": "Simple Message ☺", "username": "Username", "to": "+250788383383", "from": "2020"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -134,7 +134,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "SMSMessageData": {"Recipients": [{"status": "Success", "messageId": "1002"}] } }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"message": "My pic!\nhttps://foo.bar/image.jpg"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -145,7 +145,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "SMSMessageData": {"Recipients": [{"status": "Failed" }] } }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"message": `No External ID`}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -155,7 +155,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, ExpectedPostParams: map[string]string{"message": `Error Message`}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } @@ -169,7 +169,7 @@ var sharedSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"apikey": "KEY"}, ExpectedPostParams: map[string]string{"message": "Simple Message ☺", "username": "Username", "to": "+250788383383", "from": ""}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, diff --git a/handlers/arabiacell/arabiacell_test.go b/handlers/arabiacell/arabiacell_test.go index 8d74da833..372e47308 100644 --- a/handlers/arabiacell/arabiacell_test.go +++ b/handlers/arabiacell/arabiacell_test.go @@ -19,20 +19,20 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: "B=Msg&M=254791541111", - ExpectedStatus: 200, - ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+254791541111", + Label: "Receive Valid", + URL: receiveURL, + Data: "B=Msg&M=254791541111", + ExpectedRespStatus: 200, + ExpectedRespBody: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+254791541111", }, { - Label: "Receive Missing Number", - URL: receiveURL, - Data: "B=Msg", - ExpectedStatus: 400, - ExpectedResponse: "required field 'M'", + Label: "Receive Missing Number", + URL: receiveURL, + Data: "B=Msg", + ExpectedRespStatus: 400, + ExpectedRespBody: "required field 'M'", }, } @@ -69,7 +69,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "messageBody": "Simple Message ☺\nhttps://foo.bar/image.jpg", "chargingLevel": "0", }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "external1", SendPrep: setSendURL, }, @@ -79,7 +79,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `not xml`, MockResponseStatus: 200, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("EOF", "")}, SendPrep: setSendURL, }, @@ -89,7 +89,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `501failure`, MockResponseStatus: 200, - ExpectedStatus: "F", + ExpectedMsgStatus: "F", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid response code: 501", "")}, SendPrep: setSendURL, }, @@ -99,7 +99,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `Bad Gateway`, MockResponseStatus: 501, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } diff --git a/handlers/blackmyna/blackmyna_test.go b/handlers/blackmyna/blackmyna_test.go index 4d158d610..b1a9ea629 100644 --- a/handlers/blackmyna/blackmyna_test.go +++ b/handlers/blackmyna/blackmyna_test.go @@ -20,48 +20,48 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL + "?to=3344&smsc=ncell&from=%2B9779814641111&text=Msg", - ExpectedStatus: 200, - ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+9779814641111", + Label: "Receive Valid", + URL: receiveURL + "?to=3344&smsc=ncell&from=%2B9779814641111&text=Msg", + ExpectedRespStatus: 200, + ExpectedRespBody: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+9779814641111", }, { - Label: "Invalid URN", - URL: receiveURL + "?to=3344&smsc=ncell&from=MTN&text=Msg", - ExpectedStatus: 400, - ExpectedResponse: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL + "?to=3344&smsc=ncell&from=MTN&text=Msg", + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", }, { - Label: "Receive Empty", - URL: receiveURL + "", - ExpectedStatus: 400, - ExpectedResponse: "field 'text' required", + Label: "Receive Empty", + URL: receiveURL + "", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'text' required", }, { - Label: "Receive Missing Text", - URL: receiveURL + "?to=3344&smsc=ncell&from=%2B9779814641111", - ExpectedStatus: 400, - ExpectedResponse: "field 'text' required", + Label: "Receive Missing Text", + URL: receiveURL + "?to=3344&smsc=ncell&from=%2B9779814641111", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'text' required", }, { - Label: "Status Invalid", - URL: statusURL + "?id=bmID&status=13", - ExpectedStatus: 400, - ExpectedResponse: "unknown status", + Label: "Status Invalid", + URL: statusURL + "?id=bmID&status=13", + ExpectedRespStatus: 400, + ExpectedRespBody: "unknown status", }, { - Label: "Status Missing", - URL: statusURL + "?", - ExpectedStatus: 400, - ExpectedResponse: "field 'status' required", + Label: "Status Missing", + URL: statusURL + "?", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'status' required", }, { - Label: "Valid Status", - URL: statusURL + "?id=bmID&status=2", - ExpectedStatus: 200, - ExpectedResponse: `"status":"F"`, + Label: "Valid Status", + URL: statusURL + "?id=bmID&status=2", + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"F"`, }, } @@ -87,7 +87,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ="}, ExpectedPostParams: map[string]string{"message": "Simple Message", "address": "+250788383383", "senderaddress": "2020"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -98,7 +98,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `[{"id": "1002"}]`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"message": "☺", "address": "+250788383383", "senderaddress": "2020"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -110,7 +110,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `[{ "id": "1002" }]`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"message": "My pic!\nhttps://foo.bar/image.jpg", "address": "+250788383383", "senderaddress": "2020"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -122,7 +122,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedErrors: []courier.ChannelError{courier.NewChannelError("no external id returned in body", "")}, ExpectedPostParams: map[string]string{"message": `No External ID`, "address": "+250788383383", "senderaddress": "2020"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -132,7 +132,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, ExpectedPostParams: map[string]string{"message": `Error Message`, "address": "+250788383383", "senderaddress": "2020"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } diff --git a/handlers/bongolive/bongolive_test.go b/handlers/bongolive/bongolive_test.go index 297a51b11..215c718af 100644 --- a/handlers/bongolive/bongolive_test.go +++ b/handlers/bongolive/bongolive_test.go @@ -19,57 +19,57 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: "msgtype=1&id=12345678&message=Msg&sourceaddr=254791541111", - ExpectedStatus: 200, - ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+254791541111", + Label: "Receive Valid", + URL: receiveURL, + Data: "msgtype=1&id=12345678&message=Msg&sourceaddr=254791541111", + ExpectedRespStatus: 200, + ExpectedRespBody: "", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+254791541111", }, { - Label: "Receive Valid", - URL: receiveURL, - Data: "id=12345678&message=Msg&sourceaddr=254791541111", - ExpectedStatus: 200, - ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+254791541111", + Label: "Receive Valid", + URL: receiveURL, + Data: "id=12345678&message=Msg&sourceaddr=254791541111", + ExpectedRespStatus: 200, + ExpectedRespBody: "", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+254791541111", }, { - Label: "Receive Missing Number", - URL: receiveURL, - Data: "msgtype=1&id=12345679&message=Msg", - ExpectedStatus: 400, - ExpectedResponse: "", + Label: "Receive Missing Number", + URL: receiveURL, + Data: "msgtype=1&id=12345679&message=Msg", + ExpectedRespStatus: 400, + ExpectedRespBody: "", }, { - Label: "Status No params", - URL: receiveURL, - Data: "", - ExpectedStatus: 405, - ExpectedResponse: "", + Label: "Status No params", + URL: receiveURL, + Data: "", + ExpectedRespStatus: 405, + ExpectedRespBody: "", }, { - Label: "Status invalid params", - URL: receiveURL, - Data: "msgtype=5&dlrid=12345&status=12", - ExpectedStatus: 400, - ExpectedResponse: "", + Label: "Status invalid params", + URL: receiveURL, + Data: "msgtype=5&dlrid=12345&status=12", + ExpectedRespStatus: 400, + ExpectedRespBody: "", }, { - Label: "Status valid", - URL: receiveURL, - Data: "msgtype=5&dlrid=12345&status=1", - ExpectedStatus: 200, - ExpectedResponse: "", + Label: "Status valid", + URL: receiveURL, + Data: "msgtype=5&dlrid=12345&status=1", + ExpectedRespStatus: 200, + ExpectedRespBody: "", }, { - Label: "Invalid Msg Type", - URL: receiveURL, - Data: "msgtype=3&id=12345&status=1", - ExpectedStatus: 400, - ExpectedResponse: "", + Label: "Invalid Msg Type", + URL: receiveURL, + Data: "msgtype=3&id=12345&status=1", + ExpectedRespStatus: 400, + ExpectedRespBody: "", }, } @@ -101,7 +101,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "DLR": "1", "MESSAGE": "Simple Message ☺\nhttps://foo.bar/image.jpg", }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "123", SendPrep: setSendURL, }, @@ -120,8 +120,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ "DLR": "1", "MESSAGE": "Simple Message ☺\nhttps://foo.bar/image.jpg", }, - ExpectedStatus: "E", - SendPrep: setSendURL, + ExpectedMsgStatus: "E", + SendPrep: setSendURL, }, { Label: "Error status 403", @@ -129,7 +129,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `{"results": [{"status": "1", "msgid": "123"}]}`, MockResponseStatus: 403, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -138,7 +138,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `Bad Gateway`, MockResponseStatus: 501, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } diff --git a/handlers/burstsms/burstsms_test.go b/handlers/burstsms/burstsms_test.go index adcb4ea45..556bb25ec 100644 --- a/handlers/burstsms/burstsms_test.go +++ b/handlers/burstsms/burstsms_test.go @@ -20,32 +20,32 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL + "?response=Msg&mobile=254791541111", - ExpectedStatus: 200, - ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+254791541111", + Label: "Receive Valid", + URL: receiveURL + "?response=Msg&mobile=254791541111", + ExpectedRespStatus: 200, + ExpectedRespBody: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+254791541111", }, { - Label: "Receive Missing Number", - URL: receiveURL + "?response=Msg", - ExpectedStatus: 400, - ExpectedResponse: "required field 'mobile'", + Label: "Receive Missing Number", + URL: receiveURL + "?response=Msg", + ExpectedRespStatus: 400, + ExpectedRespBody: "required field 'mobile'", }, { Label: "Status Valid", URL: statusURL + "?message_id=12345&status=pending", - ExpectedStatus: 200, - ExpectedResponse: "Status Update Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Status Update Accepted", ExpectedExternalID: "12345", ExpectedMsgStatus: "S", }, { - Label: "Receive Invalid Status", - URL: statusURL + "?message_id=12345&status=unknown", - ExpectedStatus: 400, - ExpectedResponse: "unknown status value", + Label: "Receive Invalid Status", + URL: statusURL + "?message_id=12345&status=unknown", + ExpectedRespStatus: 400, + ExpectedRespBody: "unknown status value", }, } @@ -74,7 +74,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "message": "Simple Message ☺\nhttps://foo.bar/image.jpg", "from": "2020", }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "19835", SendPrep: setSendURL, }, @@ -84,7 +84,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `not json`, MockResponseStatus: 200, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("invalid character 'o' in literal null (expecting 'u')", "")}, SendPrep: setSendURL, }, @@ -94,7 +94,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `{ "message_id": 0 }`, MockResponseStatus: 200, - ExpectedStatus: "F", + ExpectedMsgStatus: "F", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid message id: 0", "")}, SendPrep: setSendURL, }, @@ -104,7 +104,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `Bad Gateway`, MockResponseStatus: 501, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } diff --git a/handlers/chikka/chikka_test.go b/handlers/chikka/chikka_test.go index 12b0d13cc..9eeb8cd33 100644 --- a/handlers/chikka/chikka_test.go +++ b/handlers/chikka/chikka_test.go @@ -23,61 +23,61 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive Valid", URL: receiveURL, Data: "message_type=incoming&mobile_number=639178020779&request_id=4004&message=Hello+World×tamp=1457670059.69", - ExpectedStatus: 200, - ExpectedResponse: "Message Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Message Accepted", ExpectedMsgText: Sp("Hello World"), ExpectedURN: "tel:+639178020779", ExpectedExternalID: "4004", ExpectedDate: time.Date(2016, 03, 11, 04, 20, 59, 690000128, time.UTC), }, { - Label: "Invalid URN", - URL: receiveURL, - Data: "message_type=incoming&mobile_number=MTN&request_id=4004&message=Hello+World×tamp=1457670059.69", - ExpectedStatus: 400, - ExpectedResponse: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL, + Data: "message_type=incoming&mobile_number=MTN&request_id=4004&message=Hello+World×tamp=1457670059.69", + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", }, { - Label: "Receive Mising Params", - URL: receiveURL, - Data: "message_type=incoming&message=Hello+World×tamp=1457670059.69", - ExpectedStatus: 400, - ExpectedResponse: "Field validation for 'RequestID' failed", + Label: "Receive Mising Params", + URL: receiveURL, + Data: "message_type=incoming&message=Hello+World×tamp=1457670059.69", + ExpectedRespStatus: 400, + ExpectedRespBody: "Field validation for 'RequestID' failed", }, { - Label: "Ignore Invalid message_type", - URL: receiveURL, - Data: "message_type=invalid", - ExpectedStatus: 200, - ExpectedResponse: "unknown message_type request", + Label: "Ignore Invalid message_type", + URL: receiveURL, + Data: "message_type=invalid", + ExpectedRespStatus: 200, + ExpectedRespBody: "unknown message_type request", }, { - Label: "Status Sent Valid", - URL: receiveURL, - Data: "message_type=outgoing&message_id=10&status=SENT", - ExpectedStatus: 200, - ExpectedResponse: `"status":"S"`, + Label: "Status Sent Valid", + URL: receiveURL, + Data: "message_type=outgoing&message_id=10&status=SENT", + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"S"`, }, { - Label: "Status Failed Valid", - URL: receiveURL, - Data: "message_type=outgoing&message_id=10&status=FAILED", - ExpectedStatus: 200, - ExpectedResponse: `"status":"F"`, + Label: "Status Failed Valid", + URL: receiveURL, + Data: "message_type=outgoing&message_id=10&status=FAILED", + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"F"`, }, { - Label: "Status Invalid", - URL: receiveURL, - Data: "message_type=outgoing&message_id=10&status=UNKNOWN", - ExpectedStatus: 400, - ExpectedResponse: `must be either 'SENT' or 'FAILED'`, + Label: "Status Invalid", + URL: receiveURL, + Data: "message_type=outgoing&message_id=10&status=UNKNOWN", + ExpectedRespStatus: 400, + ExpectedRespBody: `must be either 'SENT' or 'FAILED'`, }, { - Label: "Status Missing Params", - URL: receiveURL, - Data: "message_type=outgoing", - ExpectedStatus: 400, - ExpectedResponse: `Field validation for 'Status' failed `, + Label: "Status Missing Params", + URL: receiveURL, + Data: "message_type=outgoing", + ExpectedRespStatus: 400, + ExpectedRespBody: `Field validation for 'Status' failed `, }, } @@ -111,8 +111,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ "secret_key": "Password", "message_id": "10", }, - ExpectedStatus: "W", - SendPrep: setSendURL, + ExpectedMsgStatus: "W", + SendPrep: setSendURL, }, { Label: "Plain Reply", @@ -132,8 +132,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ "secret_key": "Password", "message_id": "10", }, - ExpectedStatus: "W", - SendPrep: setSendURL, + ExpectedMsgStatus: "W", + SendPrep: setSendURL, }, { Label: "Failed Reply use Send", @@ -170,14 +170,14 @@ var defaultSendTestCases = []ChannelSendTestCase{ "secret_key": "Password", "message_id": "10", }, - ExpectedStatus: "W", - SendPrep: setSendURL, + ExpectedMsgStatus: "W", + SendPrep: setSendURL, }, { Label: "Long Send", MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", MsgURN: "tel:+63911231234", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", MockResponseBody: "Success", MockResponseStatus: 200, ExpectedPostParams: map[string]string{ @@ -208,8 +208,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ "secret_key": "Password", "message_id": "10", }, - ExpectedStatus: "W", - SendPrep: setSendURL, + ExpectedMsgStatus: "W", + SendPrep: setSendURL, }, { Label: "Error Sending", @@ -227,8 +227,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ "secret_key": "Password", "message_id": "10", }, - ExpectedStatus: "E", - SendPrep: setSendURL}, + ExpectedMsgStatus: "E", + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/clickatell/clickatell_test.go b/handlers/clickatell/clickatell_test.go index 19b38ea2f..20ed559e1 100644 --- a/handlers/clickatell/clickatell_test.go +++ b/handlers/clickatell/clickatell_test.go @@ -26,7 +26,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: successSendResponse, MockResponseStatus: 200, ExpectedURLParams: map[string]string{"content": "Simple Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "id1002", SendPrep: setSendURL, }, @@ -37,7 +37,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: successSendResponse, MockResponseStatus: 200, ExpectedURLParams: map[string]string{"content": "Unicode ☺", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "id1002", SendPrep: setSendURL, }, @@ -49,7 +49,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: successSendResponse, MockResponseStatus: 200, ExpectedURLParams: map[string]string{"content": "My pic!\nhttps://foo.bar/image.jpg", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "id1002", SendPrep: setSendURL, }, @@ -60,7 +60,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `Error`, MockResponseStatus: 400, ExpectedURLParams: map[string]string{"content": "Error Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -70,7 +70,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: failSendResponse, MockResponseStatus: 200, ExpectedURLParams: map[string]string{"content": "Error Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Key path not found", "")}, SendPrep: setSendURL, }, @@ -135,8 +135,8 @@ var testCases = []ChannelHandleTestCase{ Label: "Valid Receive", URL: receiveURL, Data: receiveValidMessage, - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Hello World!"), ExpectedURN: "tel:+250788383383", ExpectedExternalID: "1234", @@ -146,79 +146,79 @@ var testCases = []ChannelHandleTestCase{ Label: "Valid Receive ISO-8859-1", URL: receiveURL, Data: receiveValidMessageISO8859_1, - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", ExpectedMsgText: Sp(`hello!`), ExpectedURN: "tel:+250788383383", ExpectedExternalID: "1234", ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC), }, { - Label: "Invalid URN", - URL: receiveURL, - Data: invalidURN, - ExpectedStatus: 400, - ExpectedResponse: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL, + Data: invalidURN, + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", }, { - Label: "Error invalid JSON", - URL: receiveURL, - Data: "foo", - ExpectedStatus: 400, - ExpectedResponse: `unable to parse request JSON`, + Label: "Error invalid JSON", + URL: receiveURL, + Data: "foo", + ExpectedRespStatus: 400, + ExpectedRespBody: `unable to parse request JSON`, }, { - Label: "Error missing JSON", - URL: receiveURL, - Data: "{}", - ExpectedStatus: 400, - ExpectedResponse: `missing one of 'messageId`, + Label: "Error missing JSON", + URL: receiveURL, + Data: "{}", + ExpectedRespStatus: 400, + ExpectedRespBody: `missing one of 'messageId`, }, { Label: "Valid Receive UTF-16BE", URL: receiveURL, Data: receiveValidMessageUTF16BE, - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("mexico k mis papas no tenýa dinero para comprarnos lo q querýamos.."), ExpectedURN: "tel:+250788383383", ExpectedExternalID: "1234", ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC), }, { - Label: "Valid Failed status report", - URL: statusURL, - Data: `{"messageId": "msg1", "statusCode": 5}`, - ExpectedStatus: 200, - ExpectedResponse: `"status":"F"`, + Label: "Valid Failed status report", + URL: statusURL, + Data: `{"messageId": "msg1", "statusCode": 5}`, + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"F"`, }, { - Label: "Valid Delivered status report", - URL: statusURL, - Data: `{"messageId": "msg1", "statusCode": 4}`, - ExpectedStatus: 200, - ExpectedResponse: `"status":"S"`, + Label: "Valid Delivered status report", + URL: statusURL, + Data: `{"messageId": "msg1", "statusCode": 4}`, + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"S"`, }, { - Label: "Unexpected status report", - URL: statusURL, - Data: `{"messageId": "msg1", "statusCode": -1}`, - ExpectedStatus: 400, - ExpectedResponse: `unknown status '-1', must be one`, + Label: "Unexpected status report", + URL: statusURL, + Data: `{"messageId": "msg1", "statusCode": -1}`, + ExpectedRespStatus: 400, + ExpectedRespBody: `unknown status '-1', must be one`, }, { - Label: "Invalid status report", - URL: statusURL, - Data: "{}", - ExpectedStatus: 400, - ExpectedResponse: `missing one of 'messageId'`, + Label: "Invalid status report", + URL: statusURL, + Data: "{}", + ExpectedRespStatus: 400, + ExpectedRespBody: `missing one of 'messageId'`, }, { - Label: "Invalid JSON", - URL: statusURL, - Data: "foo", - ExpectedStatus: 400, - ExpectedResponse: `unable to parse request JSON`, + Label: "Invalid JSON", + URL: statusURL, + Data: "foo", + ExpectedRespStatus: 400, + ExpectedRespBody: `unable to parse request JSON`, }, } diff --git a/handlers/clickmobile/clickmobile_test.go b/handlers/clickmobile/clickmobile_test.go index e68317af5..819703782 100644 --- a/handlers/clickmobile/clickmobile_test.go +++ b/handlers/clickmobile/clickmobile_test.go @@ -69,25 +69,25 @@ var handleTestCases = []ChannelHandleTestCase{ Label: "Receive Valid Message", URL: receiveURL, Data: validReceive, - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+265990099333", ExpectedExternalID: "1232434354", }, { - Label: "Invalid URN", - URL: receiveURL, - Data: invalidURNReceive, - ExpectedStatus: 400, - ExpectedResponse: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL, + Data: invalidURNReceive, + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", }, { Label: "Receive valid with empty text", URL: receiveURL, Data: validReceiveEmptyText, - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", ExpectedMsgText: Sp(""), ExpectedURN: "tel:+265990099333", ExpectedExternalID: "1232434354", @@ -96,41 +96,41 @@ var handleTestCases = []ChannelHandleTestCase{ Label: "Receive valid missing text", URL: receiveURL, Data: validMissingText, - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", ExpectedMsgText: Sp(""), ExpectedURN: "tel:+265990099333", ExpectedExternalID: "1232434354", }, { - Label: "Receive valid missing referenceID", - URL: receiveURL, - Data: validMissingReferenceID, - ExpectedStatus: 200, - ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+265990099333", + Label: "Receive valid missing referenceID", + URL: receiveURL, + Data: validMissingReferenceID, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+265990099333", }, { - Label: "Missing Shortcode", - URL: receiveURL, - Data: missingShortcode, - ExpectedStatus: 400, - ExpectedResponse: "missing parameters, must have 'mobile' and 'shortcode'", + Label: "Missing Shortcode", + URL: receiveURL, + Data: missingShortcode, + ExpectedRespStatus: 400, + ExpectedRespBody: "missing parameters, must have 'mobile' and 'shortcode'", }, { - Label: "Missing Mobile", - URL: receiveURL, - Data: missingMobile, - ExpectedStatus: 400, - ExpectedResponse: "missing parameters, must have 'mobile' and 'shortcode'", + Label: "Missing Mobile", + URL: receiveURL, + Data: missingMobile, + ExpectedRespStatus: 400, + ExpectedRespBody: "missing parameters, must have 'mobile' and 'shortcode'", }, { - Label: "Receive invalid XML", - URL: receiveURL, - Data: "empty", - ExpectedStatus: 400, - ExpectedResponse: "unable to parse request XML", + Label: "Receive invalid XML", + URL: receiveURL, + Data: "empty", + ExpectedRespStatus: 400, + ExpectedRespBody: "unable to parse request XML", }, } @@ -158,7 +158,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{"app_id":"001-app","org_id":"001-org","user_id":"Username","timestamp":"20180411182430","auth_key":"3e1347ddb444d13aa23d11e097602be0","operation":"send","reference":"10","message_type":"1","src_address":"2020","dst_address":"+250788383383","message":"Simple Message"}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -169,7 +169,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{"app_id":"001-app","org_id":"001-org","user_id":"Username","timestamp":"20180411182430","auth_key":"3e1347ddb444d13aa23d11e097602be0","operation":"send","reference":"10","message_type":"1","src_address":"2020","dst_address":"+250788383383","message":"☺"}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -180,7 +180,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedRequestBody: `{"app_id":"001-app","org_id":"001-org","user_id":"Username","timestamp":"20180411182430","auth_key":"3e1347ddb444d13aa23d11e097602be0","operation":"send","reference":"10","message_type":"1","src_address":"2020","dst_address":"+250788383383","message":"Error Message"}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -192,7 +192,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{"app_id":"001-app","org_id":"001-org","user_id":"Username","timestamp":"20180411182430","auth_key":"3e1347ddb444d13aa23d11e097602be0","operation":"send","reference":"10","message_type":"1","src_address":"2020","dst_address":"+250788383383","message":"My pic!\nhttps://foo.bar/image.jpg"}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } diff --git a/handlers/clicksend/clicksend_test.go b/handlers/clicksend/clicksend_test.go index f553421ca..4c4796bdc 100644 --- a/handlers/clicksend/clicksend_test.go +++ b/handlers/clicksend/clicksend_test.go @@ -19,22 +19,22 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: receiveURL, - Data: `from=639171234567&body=hello+world`, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedStatus: 200, - ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("hello world"), - ExpectedURN: "tel:+639171234567", + Label: "Receive Valid Message", + URL: receiveURL, + Data: `from=639171234567&body=hello+world`, + Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("hello world"), + ExpectedURN: "tel:+639171234567", }, { - Label: "Receive Missing From", - URL: receiveURL, - Data: `body=hello+world`, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedStatus: 400, - ExpectedResponse: "Error", + Label: "Receive Missing From", + URL: receiveURL, + Data: `body=hello+world`, + Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + ExpectedRespStatus: 400, + ExpectedRespBody: "Error", }, } @@ -118,7 +118,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{"messages":[{"to":"+250788383383","from":"2020","body":"Simple Message","source":"courier"}]}`, ExpectedHeaders: map[string]string{"Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "BF7AD270-0DE2-418B-B606-71D527D9C1AE", SendPrep: setSendURL, }, @@ -129,7 +129,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: successResponse, MockResponseStatus: 200, ExpectedRequestBody: `{"messages":[{"to":"+250788383383","from":"2020","body":"☺","source":"courier"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "BF7AD270-0DE2-418B-B606-71D527D9C1AE", SendPrep: setSendURL, }, @@ -142,7 +142,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{"messages":[{"to":"+250788383383","from":"2020","body":"My pic!\nhttps://foo.bar/image.jpg","source":"courier"}]}`, ExpectedExternalID: "BF7AD270-0DE2-418B-B606-71D527D9C1AE", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -151,7 +151,7 @@ var sendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `[{"Response": "101"}]`, MockResponseStatus: 403, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -160,7 +160,7 @@ var sendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: failureResponse, MockResponseStatus: 200, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received non SUCCESS status: FAILURE", "")}, SendPrep: setSendURL, }, diff --git a/handlers/dart/dart_test.go b/handlers/dart/dart_test.go index 98a59c222..b9315ed8a 100644 --- a/handlers/dart/dart_test.go +++ b/handlers/dart/dart_test.go @@ -20,66 +20,66 @@ const ( var daTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL + "?userid=testusr&password=test&original=6289881134560&sendto=2020&message=Msg", - ExpectedStatus: 200, - ExpectedResponse: "000", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+6289881134560", + Label: "Receive Valid", + URL: receiveURL + "?userid=testusr&password=test&original=6289881134560&sendto=2020&message=Msg", + ExpectedRespStatus: 200, + ExpectedRespBody: "000", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+6289881134560", }, { - Label: "Receive Valid", - URL: receiveURL + "?userid=testusr&password=test&original=cmp-oodddqddwdwdcd&sendto=2020&message=Msg", - ExpectedStatus: 200, - ExpectedResponse: "000", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "ext:cmp-oodddqddwdwdcd", + Label: "Receive Valid", + URL: receiveURL + "?userid=testusr&password=test&original=cmp-oodddqddwdwdcd&sendto=2020&message=Msg", + ExpectedRespStatus: 200, + ExpectedRespBody: "000", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "ext:cmp-oodddqddwdwdcd", }, { - Label: "Receive Invalid", - URL: receiveURL, - ExpectedStatus: 400, - ExpectedResponse: "missing required parameters original and sendto", + Label: "Receive Invalid", + URL: receiveURL, + ExpectedRespStatus: 400, + ExpectedRespBody: "missing required parameters original and sendto", }, { - Label: "Valid Status", - URL: statusURL + "?status=10&messageid=12345", - ExpectedStatus: 200, - ExpectedResponse: "000", - ExpectedMsgStatus: "D", + Label: "Valid Status", + URL: statusURL + "?status=10&messageid=12345", + ExpectedRespStatus: 200, + ExpectedRespBody: "000", + ExpectedMsgStatus: "D", }, { - Label: "Valid Status", - URL: statusURL + "?status=10&messageid=12345.2", - ExpectedStatus: 200, - ExpectedResponse: "000", - ExpectedMsgStatus: "D", + Label: "Valid Status", + URL: statusURL + "?status=10&messageid=12345.2", + ExpectedRespStatus: 200, + ExpectedRespBody: "000", + ExpectedMsgStatus: "D", }, { - Label: "Failed Status", - URL: statusURL + "?status=30&messageid=12345", - ExpectedStatus: 200, - ExpectedResponse: "000", - ExpectedMsgStatus: "F", + Label: "Failed Status", + URL: statusURL + "?status=30&messageid=12345", + ExpectedRespStatus: 200, + ExpectedRespBody: "000", + ExpectedMsgStatus: "F", }, { - Label: "Missing Status", - URL: statusURL + "?messageid=12345", - ExpectedStatus: 400, - ExpectedResponse: "parameters messageid and status should not be empty", + Label: "Missing Status", + URL: statusURL + "?messageid=12345", + ExpectedRespStatus: 400, + ExpectedRespBody: "parameters messageid and status should not be empty", }, { - Label: "Missing Status", - URL: statusURL + "?status=foo&messageid=12345", - ExpectedStatus: 400, - ExpectedResponse: "parsing failed: status 'foo' is not an integer", + Label: "Missing Status", + URL: statusURL + "?status=foo&messageid=12345", + ExpectedRespStatus: 400, + ExpectedRespBody: "parsing failed: status 'foo' is not an integer", }, { - Label: "Missing Status", - URL: statusURL + "?status=10&messageid=abc", - ExpectedStatus: 400, - ExpectedResponse: "parsing failed: messageid 'abc' is not an integer", + Label: "Missing Status", + URL: statusURL + "?status=10&messageid=abc", + ExpectedRespStatus: 400, + ExpectedRespBody: "parsing failed: messageid 'abc' is not an integer", }, } @@ -105,7 +105,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: "000", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -115,7 +115,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: "000", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"message": "I need to keep adding more things to make it work", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10.2"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -126,7 +126,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: "000", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"message": "My pic!\nhttps://foo.bar/image.jpg", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -136,7 +136,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `Error`, MockResponseStatus: 400, ExpectedURLParams: map[string]string{"message": "Error Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -146,7 +146,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: "001", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Error 001: Authentication Error", "")}, SendPrep: setSendURL, }, @@ -157,7 +157,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: "101", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Error 101: Account expired or invalid parameters", "")}, SendPrep: setSendURL, }, diff --git a/handlers/discord/discord_test.go b/handlers/discord/discord_test.go index abe04cbe4..e95e735e7 100644 --- a/handlers/discord/discord_test.go +++ b/handlers/discord/discord_test.go @@ -24,55 +24,55 @@ var testChannels = []courier.Channel{ var testCases = []ChannelHandleTestCase{ { - Label: "Recieve Message", - URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", - Data: `from=694634743521607802&text=hello`, - ExpectedStatus: 200, - ExpectedMsgText: Sp("hello"), - ExpectedURN: "discord:694634743521607802", + Label: "Recieve Message", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", + Data: `from=694634743521607802&text=hello`, + ExpectedRespStatus: 200, + ExpectedMsgText: Sp("hello"), + ExpectedURN: "discord:694634743521607802", }, { Label: "Recieve Message with attachment", URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", Data: `from=694634743521607802&text=hello&attachments=https://test.test/foo.png`, - ExpectedStatus: 200, + ExpectedRespStatus: 200, ExpectedMsgText: Sp("hello"), ExpectedURN: "discord:694634743521607802", ExpectedAttachments: []string{"https://test.test/foo.png"}, }, { - Label: "Invalid ID", - URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", - Data: `from=somebody&text=hello`, - ExpectedStatus: 400, - ExpectedResponse: "Error", + Label: "Invalid ID", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", + Data: `from=somebody&text=hello`, + ExpectedRespStatus: 400, + ExpectedRespBody: "Error", }, { - Label: "Garbage Body", - URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", - Data: `sdfaskdfajsdkfajsdfaksdf`, - ExpectedStatus: 400, - ExpectedResponse: "Error", + Label: "Garbage Body", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", + Data: `sdfaskdfajsdkfajsdfaksdf`, + ExpectedRespStatus: 400, + ExpectedRespBody: "Error", }, { - Label: "Missing Text", - URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", - Data: `from=694634743521607802`, - ExpectedStatus: 400, - ExpectedResponse: "Error", + Label: "Missing Text", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", + Data: `from=694634743521607802`, + ExpectedRespStatus: 400, + ExpectedRespBody: "Error", }, { - Label: "Message Sent Handler", - URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/sent/", - Data: `id=12345`, - ExpectedStatus: 200, - ExpectedResponse: `"status":"S"`, + Label: "Message Sent Handler", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/sent/", + Data: `id=12345`, + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"S"`, }, { - Label: "Message Sent Handler Garbage", - URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/sent/", - Data: `nothing`, - ExpectedStatus: 400, + Label: "Message Sent Handler Garbage", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/sent/", + Data: `nothing`, + ExpectedRespStatus: 400, }, } diff --git a/handlers/dmark/dmark_test.go b/handlers/dmark/dmark_test.go index 257e46369..b3f5246f7 100644 --- a/handlers/dmark/dmark_test.go +++ b/handlers/dmark/dmark_test.go @@ -21,63 +21,63 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: "text=Msg&short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=254791541111", - ExpectedStatus: 200, - ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+254791541111", - ExpectedDate: time.Date(2017, 10, 26, 15, 51, 32, 906335000, time.UTC), + Label: "Receive Valid", + URL: receiveURL, + Data: "text=Msg&short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=254791541111", + ExpectedRespStatus: 200, + ExpectedRespBody: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+254791541111", + ExpectedDate: time.Date(2017, 10, 26, 15, 51, 32, 906335000, time.UTC), }, { - Label: "Invalid URN", - URL: receiveURL, - Data: "text=Msg&short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=MTN", - ExpectedStatus: 400, - ExpectedResponse: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL, + Data: "text=Msg&short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=MTN", + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", }, { - Label: "Receive Empty", - URL: receiveURL, - Data: "empty", - ExpectedStatus: 400, - ExpectedResponse: "field 'msisdn' required", + Label: "Receive Empty", + URL: receiveURL, + Data: "empty", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'msisdn' required", }, { - Label: "Receive Missing Text", - URL: receiveURL, - Data: "short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=254791541111", - ExpectedStatus: 400, - ExpectedResponse: "field 'text' required", + Label: "Receive Missing Text", + URL: receiveURL, + Data: "short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=254791541111", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'text' required", }, { - Label: "Receive Invalid TS", - URL: receiveURL, - Data: "text=Msg&short_code=2020&tstamp=2017-10-26&msisdn=254791541111", - ExpectedStatus: 400, - ExpectedResponse: "invalid tstamp", + Label: "Receive Invalid TS", + URL: receiveURL, + Data: "text=Msg&short_code=2020&tstamp=2017-10-26&msisdn=254791541111", + ExpectedRespStatus: 400, + ExpectedRespBody: "invalid tstamp", }, { - Label: "Status Invalid", - URL: statusURL, - ExpectedStatus: 400, - Data: "id=12345&status=Borked", - ExpectedResponse: "unknown status", + Label: "Status Invalid", + URL: statusURL, + ExpectedRespStatus: 400, + Data: "id=12345&status=Borked", + ExpectedRespBody: "unknown status", }, { - Label: "Status Missing", - URL: statusURL, - ExpectedStatus: 400, - Data: "id=12345", - ExpectedResponse: "field 'status' required", + Label: "Status Missing", + URL: statusURL, + ExpectedRespStatus: 400, + Data: "id=12345", + ExpectedRespBody: "field 'status' required", }, { - Label: "Status Valid", - URL: statusURL, - ExpectedStatus: 200, - Data: "id=12345&status=1", - ExpectedResponse: `"status":"D"`, + Label: "Status Valid", + URL: statusURL, + ExpectedRespStatus: 200, + Data: "id=12345&status=1", + ExpectedRespBody: `"status":"D"`, }, } @@ -104,7 +104,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "Token Authy"}, ExpectedPostParams: map[string]string{"text": "Simple Message ☺", "receiver": "250788383383", "sender": "2020", "dlr_url": "https://localhost/c/dk/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%s"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -115,7 +115,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "Token Authy"}, ExpectedPostParams: map[string]string{"text": "Error Message", "receiver": "250788383383", "sender": "2020"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sms_id from body", "")}, SendPrep: setSendURL, }, @@ -127,7 +127,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedHeaders: map[string]string{"Authorization": "Token Authy"}, ExpectedPostParams: map[string]string{"text": "Error Message", "receiver": "250788383383", "sender": "2020"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } diff --git a/handlers/external/external_test.go b/handlers/external/external_test.go index cae2f1a82..e2972edae 100644 --- a/handlers/external/external_test.go +++ b/handlers/external/external_test.go @@ -26,160 +26,160 @@ var gmChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: receiveURL + "?sender=%2B2349067554729&text=Join", - Data: "empty", - ExpectedStatus: 200, - ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", - }, + Label: "Receive Valid Message", + URL: receiveURL + "?sender=%2B2349067554729&text=Join", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + }, { - Label: "Receive Valid Post", - URL: receiveURL, - Data: "sender=%2B2349067554729&text=Join", - ExpectedStatus: 200, - ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", + Label: "Receive Valid Post", + URL: receiveURL, + Data: "sender=%2B2349067554729&text=Join", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", }, { - Label: "Receive Valid Post multipart form", - URL: receiveURL, - MultipartFormFields: map[string]string{"sender": "2349067554729", "text": "Join"}, - ExpectedStatus: 200, - ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", + Label: "Receive Valid Post multipart form", + URL: receiveURL, + MultipartForm: map[string]string{"sender": "2349067554729", "text": "Join"}, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", }, { - Label: "Receive Valid From", - URL: receiveURL + "?from=%2B2349067554729&text=Join", - Data: "empty", - ExpectedStatus: 200, - ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", + Label: "Receive Valid From", + URL: receiveURL + "?from=%2B2349067554729&text=Join", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", }, { - Label: "Receive Country Parse", - URL: receiveURL + "?from=2349067554729&text=Join", - Data: "empty", - ExpectedStatus: 200, - ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", + Label: "Receive Country Parse", + URL: receiveURL + "?from=2349067554729&text=Join", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", }, { - Label: "Receive Valid Message With Date", - URL: receiveURL + "?sender=%2B2349067554729&text=Join&date=2017-06-23T12:30:00.500Z", - Data: "empty", - ExpectedStatus: 200, - ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", - ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC), + Label: "Receive Valid Message With Date", + URL: receiveURL + "?sender=%2B2349067554729&text=Join&date=2017-06-23T12:30:00.500Z", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC), }, { - Label: "Receive Valid Message With Time", - URL: receiveURL + "?sender=%2B2349067554729&text=Join&time=2017-06-23T12:30:00Z", - Data: "empty", - ExpectedStatus: 200, - ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", - ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC), + Label: "Receive Valid Message With Time", + URL: receiveURL + "?sender=%2B2349067554729&text=Join&time=2017-06-23T12:30:00Z", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC), }, { - Label: "Invalid URN", - URL: receiveURL + "?sender=MTN&text=Join", - Data: "empty", - ExpectedStatus: 400, - ExpectedResponse: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL + "?sender=MTN&text=Join", + Data: "empty", + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", }, { - Label: "Receive No Params", - URL: receiveURL, - Data: "empty", - ExpectedStatus: 400, - ExpectedResponse: "must have one of 'sender' or 'from' set", + Label: "Receive No Params", + URL: receiveURL, + Data: "empty", + ExpectedRespStatus: 400, + ExpectedRespBody: "must have one of 'sender' or 'from' set", }, { - Label: "Receive No Sender", - URL: receiveURL + "?text=Join", - Data: "empty", - ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from' set", + Label: "Receive No Sender", + URL: receiveURL + "?text=Join", + Data: "empty", + ExpectedRespStatus: 400, ExpectedRespBody: "must have one of 'sender' or 'from' set", }, { - Label: "Receive Invalid Date", - URL: receiveURL + "?sender=%2B2349067554729&text=Join&time=20170623T123000Z", - Data: "empty", - ExpectedStatus: 400, - ExpectedResponse: "invalid date format, must be RFC 3339", + Label: "Receive Invalid Date", + URL: receiveURL + "?sender=%2B2349067554729&text=Join&time=20170623T123000Z", + Data: "empty", + ExpectedRespStatus: 400, + ExpectedRespBody: "invalid date format, must be RFC 3339", }, { - Label: "Failed No Params", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/failed/", - ExpectedStatus: 400, - ExpectedResponse: "field 'id' required", + Label: "Failed No Params", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/failed/", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'id' required", }, { - Label: "Failed Valid", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/failed/?id=12345", - ExpectedStatus: 200, - ExpectedResponse: `"status":"F"`, + Label: "Failed Valid", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/failed/?id=12345", + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"F"`, }, { - Label: "Invalid Status", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/wired/", - ExpectedStatus: 404, - ExpectedResponse: `page not found`, + Label: "Invalid Status", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/wired/", + ExpectedRespStatus: 404, + ExpectedRespBody: `page not found`, }, { - Label: "Sent Valid", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/sent/?id=12345", - ExpectedStatus: 200, - ExpectedResponse: `"status":"S"`}, + Label: "Sent Valid", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/sent/?id=12345", + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"S"`}, { - Label: "Delivered Valid", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered/?id=12345", - ExpectedStatus: 200, - Data: "nothing", - ExpectedResponse: `"status":"D"`, + Label: "Delivered Valid", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered/?id=12345", + ExpectedRespStatus: 200, + Data: "nothing", + ExpectedRespBody: `"status":"D"`, }, { - Label: "Delivered Valid Post", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered/", - Data: "id=12345", - ExpectedStatus: 200, - ExpectedResponse: `"status":"D"`, + Label: "Delivered Valid Post", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered/", + Data: "id=12345", + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"D"`, }, { - Label: "Stopped Event", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/?from=%2B2349067554729", - ExpectedStatus: 200, - Data: "nothing", - ExpectedResponse: "Accepted", + Label: "Stopped Event", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/?from=%2B2349067554729", + ExpectedRespStatus: 200, + Data: "nothing", + ExpectedRespBody: "Accepted", }, { - Label: "Stopped Event Post", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/", - Data: "from=%2B2349067554729", - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + Label: "Stopped Event Post", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/", + Data: "from=%2B2349067554729", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", }, { - Label: "Stopped Event Invalid URN", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/?from=MTN", - Data: "empty", - ExpectedStatus: 400, - ExpectedResponse: "phone number supplied is not a number", + Label: "Stopped Event Invalid URN", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/?from=MTN", + Data: "empty", + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", }, { - Label: "Stopped event No Params", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/", - ExpectedStatus: 400, - ExpectedResponse: "field 'from' required", + Label: "Stopped event No Params", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'from' required", }, } @@ -196,32 +196,32 @@ var testSOAPReceiveChannels = []courier.Channel{ var handleSOAPReceiveTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Post SOAP", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", - Data: `2349067554729Join`, - ExpectedStatus: 200, - ExpectedResponse: "0", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", + Label: "Receive Valid Post SOAP", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + Data: `2349067554729Join`, + ExpectedRespStatus: 200, + ExpectedRespBody: "0", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", }, { - Label: "Receive Invalid SOAP", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", - Data: ``, - ExpectedStatus: 400, - ExpectedResponse: "missing from", + Label: "Receive Invalid SOAP", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + Data: ``, + ExpectedRespStatus: 400, + ExpectedRespBody: "missing from", }, } var gmTestCases = []ChannelHandleTestCase{ { - Label: "Receive Non Plus Message", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sender=2207222333&text=Join", - Data: "empty", - ExpectedStatus: 200, - ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2207222333", + Label: "Receive Non Plus Message", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sender=2207222333&text=Join", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2207222333", }, } @@ -237,21 +237,21 @@ var customChannels = []courier.Channel{ var customTestCases = []ChannelHandleTestCase{ { - Label: "Receive Custom Message", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?from_number=12067799192&messageText=Join×tamp=2017-06-23T12:30:00Z", - Data: "empty", - ExpectedStatus: 200, - ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+12067799192", - ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC), + Label: "Receive Custom Message", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?from_number=12067799192&messageText=Join×tamp=2017-06-23T12:30:00Z", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+12067799192", + ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC), }, { - Label: "Receive Custom Missing", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sent_from=12067799192&messageText=Join", - Data: "empty", - ExpectedStatus: 400, - ExpectedResponse: "must have one of 'sender' or 'from' set", + Label: "Receive Custom Missing", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sent_from=12067799192&messageText=Join", + Data: "empty", + ExpectedRespStatus: 400, + ExpectedRespBody: "must have one of 'sender' or 'from' set", }, } @@ -283,7 +283,7 @@ var longSendTestCases = []ChannelSendTestCase{ MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"text": "characters", "to": "+250788383383", "from": "2020", "quick_reply": "One"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } @@ -297,7 +297,7 @@ var getSendSmartEncodingTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"text": `Fancy "Smart" Quotes`, "to": "+250788383383", "from": "2020"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } @@ -311,7 +311,7 @@ var postSendSmartEncodingTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": `Fancy "Smart" Quotes`, "to": "+250788383383", "from": "2020"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } @@ -325,7 +325,7 @@ var getSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"text": "Simple Message", "to": "+250788383383", "from": "2020"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -335,7 +335,7 @@ var getSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"text": "☺", "to": "+250788383383", "from": "2020"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -346,7 +346,7 @@ var getSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedURLParams: map[string]string{"text": `Error Message`, "to": "+250788383383"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -358,7 +358,7 @@ var getSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "+250788383383", "from": "2020"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } @@ -372,7 +372,7 @@ var postSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "+250788383383", "from": "2020"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -383,7 +383,7 @@ var postSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "☺", "to": "+250788383383", "from": "2020"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -394,7 +394,7 @@ var postSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"text": `Error Message`, "to": "+250788383383"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -405,7 +405,7 @@ var postSendTestCases = []ChannelSendTestCase{ MockResponseBody: `0: Accepted for delivery`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "+250788383383", "from": "2020"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } @@ -419,7 +419,7 @@ var postSendCustomContentTypeTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded; charset=utf-8"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } @@ -433,7 +433,7 @@ var jsonSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{ "to":"+250788383383", "text":"Simple Message", "from":"2020", "quick_replies":[] }`, ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -444,7 +444,7 @@ var jsonSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{ "to":"+250788383383", "text":"☺ \"hi!\"", "from":"2020", "quick_replies":[] }`, ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -455,7 +455,7 @@ var jsonSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedRequestBody: `{ "to":"+250788383383", "text":"Error Message", "from":"2020", "quick_replies":[] }`, ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -467,7 +467,7 @@ var jsonSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{ "to":"+250788383383", "text":"My pic!\nhttps://foo.bar/image.jpg", "from":"2020", "quick_replies":[] }`, ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL}, { Label: "Send Quick Replies", @@ -478,7 +478,7 @@ var jsonSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{ "to":"+250788383383", "text":"Some message", "from":"2020", "quick_replies":["One","Two","Three"] }`, ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } @@ -493,7 +493,7 @@ var jsonLongSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{ "to":"+250788383383", "text":"characters", "from":"2020", "quick_replies":["One","Two","Three"] }`, ExpectedHeaders: map[string]string{"Authorization": "Token ABCDEF", "Content-Type": "application/json"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } @@ -507,7 +507,7 @@ var xmlSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `+250788383383Simple Message2020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -518,7 +518,7 @@ var xmlSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `+2507883833832020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -529,7 +529,7 @@ var xmlSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedRequestBody: `+250788383383Error Message2020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -541,7 +541,7 @@ var xmlSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `+250788383383My pic! https://foo.bar/image.jpg2020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -553,7 +553,7 @@ var xmlSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: "+250788383383Some message2020OneTwoThree", ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } @@ -568,7 +568,7 @@ var xmlLongSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: "+250788383383characters2020OneTwoThree", ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } @@ -578,7 +578,7 @@ var xmlSendWithResponseContentTestCases = []ChannelSendTestCase{ Label: "Plain Send", MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", MockResponseBody: "0", MockResponseStatus: 200, ExpectedRequestBody: `+250788383383Simple Message2020`, @@ -593,7 +593,7 @@ var xmlSendWithResponseContentTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `+2507883833832020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -604,7 +604,7 @@ var xmlSendWithResponseContentTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedRequestBody: `+250788383383Error Message2020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -615,7 +615,7 @@ var xmlSendWithResponseContentTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `+250788383383Error Message2020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid response content: 1", "")}, SendPrep: setSendURL, }, @@ -628,7 +628,7 @@ var xmlSendWithResponseContentTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `+250788383383My pic! https://foo.bar/image.jpg2020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -640,7 +640,7 @@ var xmlSendWithResponseContentTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `+250788383383Some message2020OneTwoThree`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } @@ -654,7 +654,7 @@ var nationalGetSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"text": "Simple Message", "to": "788383383", "from": "2020"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index 6f61ad1e0..0b5379e51 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -422,8 +422,8 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive Message", URL: receiveURL, Data: helloMsg, - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", ExpectedMsgText: Sp("Hello World"), ExpectedURN: "facebook:5678", ExpectedExternalID: "external_id", @@ -433,8 +433,8 @@ var testCases = []ChannelHandleTestCase{ Label: "No Duplicate Receive Message", URL: receiveURL, Data: duplicateMsg, - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", ExpectedMsgText: Sp("Hello World"), ExpectedURN: "facebook:5678", ExpectedExternalID: "external_id", @@ -444,8 +444,8 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive Attachment", URL: receiveURL, Data: attachment, - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, ExpectedURN: "facebook:5678", @@ -456,8 +456,8 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive Location", URL: receiveURL, Data: locationAttachment, - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, ExpectedURN: "facebook:5678", @@ -468,144 +468,144 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive Thumbs Up", URL: receiveURL, Data: thumbsUp, - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", ExpectedMsgText: Sp("👍"), ExpectedURN: "facebook:5678", ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), }, { - Label: "Receive OptIn UserRef", - URL: receiveURL, - Data: optInUserRef, - ExpectedStatus: 200, - ExpectedResponse: "Handled", - ExpectedURN: "facebook:ref:optin_user_ref", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.Referral, - ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, + Label: "Receive OptIn UserRef", + URL: receiveURL, + Data: optInUserRef, + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", + ExpectedURN: "facebook:ref:optin_user_ref", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, }, { - Label: "Receive OptIn", - URL: receiveURL, - Data: optIn, - ExpectedStatus: 200, - ExpectedResponse: "Handled", - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.Referral, - ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, + Label: "Receive OptIn", + URL: receiveURL, + Data: optIn, + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, }, { - Label: "Receive Get Started", - URL: receiveURL, - Data: postbackGetStarted, - ExpectedStatus: 200, - ExpectedResponse: "Handled", - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.NewConversation, - ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, + Label: "Receive Get Started", + URL: receiveURL, + Data: postbackGetStarted, + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.NewConversation, + ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, }, { - Label: "Receive Referral Postback", - URL: receiveURL, - Data: postback, - ExpectedStatus: 200, - ExpectedResponse: "Handled", - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.Referral, - ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, + Label: "Receive Referral Postback", + URL: receiveURL, + Data: postback, + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, }, { - Label: "Receive Referral", - URL: receiveURL, - Data: postbackReferral, - ExpectedStatus: 200, - ExpectedResponse: "Handled", - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.Referral, - ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, + Label: "Receive Referral", + URL: receiveURL, + Data: postbackReferral, + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, }, { - Label: "Receive Referral", - URL: receiveURL, - Data: referral, - ExpectedStatus: 200, - ExpectedResponse: `"referrer_id":"referral id"`, - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.Referral, - ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, + Label: "Receive Referral", + URL: receiveURL, + Data: referral, + ExpectedRespStatus: 200, + ExpectedRespBody: `"referrer_id":"referral id"`, + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, }, { Label: "Receive DLR", URL: receiveURL, Data: dlr, - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "mid.1458668856218:ed81099e15d3f4f233", }, { - Label: "Different Page", - URL: receiveURL, - Data: differentPage, - ExpectedStatus: 200, - ExpectedResponse: `"data":[]`, + Label: "Different Page", + URL: receiveURL, + Data: differentPage, + ExpectedRespStatus: 200, + ExpectedRespBody: `"data":[]`, }, { - Label: "Echo", - URL: receiveURL, - Data: echo, - ExpectedStatus: 200, - ExpectedResponse: `ignoring echo`, + Label: "Echo", + URL: receiveURL, + Data: echo, + ExpectedRespStatus: 200, + ExpectedRespBody: `ignoring echo`, }, { - Label: "Not Page", - URL: receiveURL, - Data: notPage, - ExpectedStatus: 200, - ExpectedResponse: "ignoring", + Label: "Not Page", + URL: receiveURL, + Data: notPage, + ExpectedRespStatus: 200, + ExpectedRespBody: "ignoring", }, { - Label: "No Entries", - URL: receiveURL, - Data: noEntries, - ExpectedStatus: 200, - ExpectedResponse: "ignoring", + Label: "No Entries", + URL: receiveURL, + Data: noEntries, + ExpectedRespStatus: 200, + ExpectedRespBody: "ignoring", }, { - Label: "No Messaging Entries", - URL: receiveURL, - Data: noMessagingEntries, - ExpectedStatus: 200, - ExpectedResponse: "Handled", + Label: "No Messaging Entries", + URL: receiveURL, + Data: noMessagingEntries, + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", }, { - Label: "Unknown Messaging Entry", - URL: receiveURL, - Data: unkownMessagingEntry, - ExpectedStatus: 200, - ExpectedResponse: "Handled", + Label: "Unknown Messaging Entry", + URL: receiveURL, + Data: unkownMessagingEntry, + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", }, { - Label: "Not JSON", - URL: receiveURL, - Data: `blargh`, - ExpectedStatus: 400, - ExpectedResponse: "Error", + Label: "Not JSON", + URL: receiveURL, + Data: `blargh`, + ExpectedRespStatus: 400, + ExpectedRespBody: "Error", }, { - Label: "Invalid URN", - URL: receiveURL, - Data: invalidURN, - ExpectedStatus: 400, - ExpectedResponse: "invalid facebook id", + Label: "Invalid URN", + URL: receiveURL, + Data: invalidURN, + ExpectedRespStatus: 400, + ExpectedRespBody: "invalid facebook id", }, } @@ -692,34 +692,34 @@ func TestVerify(t *testing.T) { RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ { - Label: "Receive Message", - URL: receiveURL, - Data: helloMsg, - ExpectedStatus: 200, + Label: "Receive Message", + URL: receiveURL, + Data: helloMsg, + ExpectedRespStatus: 200, }, { - Label: "Verify No Mode", - URL: receiveURL, - ExpectedStatus: 400, - ExpectedResponse: "unknown request", + Label: "Verify No Mode", + URL: receiveURL, + ExpectedRespStatus: 400, + ExpectedRespBody: "unknown request", }, { - Label: "Verify No Secret", - URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe", - ExpectedStatus: 400, - ExpectedResponse: "token does not match secret", + Label: "Verify No Secret", + URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe", + ExpectedRespStatus: 400, + ExpectedRespBody: "token does not match secret", }, { - Label: "Invalid Secret", - URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe&hub.verify_token=blah", - ExpectedStatus: 400, - ExpectedResponse: "token does not match secret", + Label: "Invalid Secret", + URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe&hub.verify_token=blah", + ExpectedRespStatus: 400, + ExpectedRespBody: "token does not match secret", }, { - Label: "Valid Secret", - URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe&hub.verify_token=mysecret&hub.challenge=yarchallenge", - ExpectedStatus: 200, - ExpectedResponse: "yarchallenge", + Label: "Valid Secret", + URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe&hub.verify_token=mysecret&hub.challenge=yarchallenge", + ExpectedRespStatus: 200, + ExpectedRespBody: "yarchallenge", }, }) @@ -744,7 +744,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -756,7 +756,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"RESPONSE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -768,7 +768,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"user_ref":"67890"},"message":{"text":"Simple Message"}}`, ExpectedContactURNs: map[string]bool{"facebook:12345": true, "ext:67890": true, "facebook:ref:67890": false}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -780,7 +780,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"id":"12345"},"message":{"text":"Are you happy?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -790,7 +790,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "facebook:12345", MsgQuickReplies: []string{"Yes", "No"}, MsgTopic: "account", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, @@ -801,7 +801,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Label: "Send Photo", MsgURN: "facebook:12345", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, @@ -818,7 +818,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"CONFIRMED_EVENT_UPDATE","recipient":{"id":"12345"},"message":{"text":"This is some text.","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -829,7 +829,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"NON_PROMOTIONAL_SUBSCRIPTION","recipient":{"id":"12345"},"message":{"attachment":{"type":"file","payload":{"url":"https://foo.bar/document.pdf","is_reusable":true}}}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -839,7 +839,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "facebook:12345", MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, SendPrep: setSendURL, }, @@ -849,7 +849,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "facebook:12345", MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 403, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index d9002948d..7eab23752 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -35,8 +35,8 @@ var testCasesFBA = []ChannelHandleTestCase{ Label: "Receive Message FBA", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Hello World"), @@ -46,19 +46,19 @@ var testCasesFBA = []ChannelHandleTestCase{ PrepRequest: addValidSignature, }, { - Label: "Receive Invalid Signature", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), - ExpectedStatus: 400, - ExpectedResponse: "invalid request signature", - PrepRequest: addInvalidSignature, + Label: "Receive Invalid Signature", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), + ExpectedRespStatus: 400, + ExpectedRespBody: "invalid request signature", + PrepRequest: addInvalidSignature, }, { Label: "No Duplicate Receive Message", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/duplicateMsgFBA.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", ExpectedMsgText: Sp("Hello World"), ExpectedURN: "facebook:5678", ExpectedExternalID: "external_id", @@ -69,8 +69,8 @@ var testCasesFBA = []ChannelHandleTestCase{ Label: "Receive Attachment", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/attachmentFBA.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, ExpectedURN: "facebook:5678", @@ -82,8 +82,8 @@ var testCasesFBA = []ChannelHandleTestCase{ Label: "Receive Location", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/locationAttachment.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, ExpectedURN: "facebook:5678", @@ -95,8 +95,8 @@ var testCasesFBA = []ChannelHandleTestCase{ Label: "Receive Thumbs Up", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/thumbsUp.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", ExpectedMsgText: Sp("👍"), ExpectedURN: "facebook:5678", ExpectedExternalID: "external_id", @@ -104,151 +104,151 @@ var testCasesFBA = []ChannelHandleTestCase{ PrepRequest: addValidSignature, }, { - Label: "Receive OptIn UserRef", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/optInUserRef.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", - ExpectedURN: "facebook:ref:optin_user_ref", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.Referral, - ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, - PrepRequest: addValidSignature, - }, - { - Label: "Receive OptIn", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/optIn.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.Referral, - ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, - PrepRequest: addValidSignature, - }, - { - Label: "Receive Get Started", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/postbackGetStarted.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.NewConversation, - ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, - PrepRequest: addValidSignature, - }, - { - Label: "Receive Referral Postback", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/postback.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.Referral, - ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, - PrepRequest: addValidSignature, - }, - { - Label: "Receive Referral", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/postbackReferral.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.Referral, - ExpectedChannelEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, - PrepRequest: addValidSignature, - }, - { - Label: "Receive Referral", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/referral.json")), - ExpectedStatus: 200, - ExpectedResponse: `"referrer_id":"referral id"`, - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.Referral, - ExpectedChannelEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, - PrepRequest: addValidSignature, + Label: "Receive OptIn UserRef", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/optInUserRef.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", + ExpectedURN: "facebook:ref:optin_user_ref", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, + PrepRequest: addValidSignature, + }, + { + Label: "Receive OptIn", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/optIn.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, + PrepRequest: addValidSignature, + }, + { + Label: "Receive Get Started", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/postbackGetStarted.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.NewConversation, + ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, + PrepRequest: addValidSignature, + }, + { + Label: "Receive Referral Postback", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/postback.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, + PrepRequest: addValidSignature, + }, + { + Label: "Receive Referral", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/postbackReferral.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, + PrepRequest: addValidSignature, + }, + { + Label: "Receive Referral", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/referral.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: `"referrer_id":"referral id"`, + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, + PrepRequest: addValidSignature, }, { Label: "Receive DLR", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/dlr.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "mid.1458668856218:ed81099e15d3f4f233", PrepRequest: addValidSignature, }, { - Label: "Different Page", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/differentPageFBA.json")), - ExpectedStatus: 200, - ExpectedResponse: `"data":[]`, - PrepRequest: addValidSignature, + Label: "Different Page", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/differentPageFBA.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: `"data":[]`, + PrepRequest: addValidSignature, }, { - Label: "Echo", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/echoFBA.json")), - ExpectedStatus: 200, - ExpectedResponse: `ignoring echo`, - PrepRequest: addValidSignature, + Label: "Echo", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/echoFBA.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: `ignoring echo`, + PrepRequest: addValidSignature, }, { - Label: "Not Page", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/notPage.json")), - ExpectedStatus: 400, - ExpectedResponse: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notpage", - PrepRequest: addValidSignature, + Label: "Not Page", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/notPage.json")), + ExpectedRespStatus: 400, + ExpectedRespBody: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notpage", + PrepRequest: addValidSignature, }, { - Label: "No Entries", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/noEntriesFBA.json")), - ExpectedStatus: 400, - ExpectedResponse: "no entries found", - PrepRequest: addValidSignature, + Label: "No Entries", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/noEntriesFBA.json")), + ExpectedRespStatus: 400, + ExpectedRespBody: "no entries found", + PrepRequest: addValidSignature, }, { - Label: "No Messaging Entries", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/noMessagingEntriesFBA.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", - PrepRequest: addValidSignature, + Label: "No Messaging Entries", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/noMessagingEntriesFBA.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", + PrepRequest: addValidSignature, }, { - Label: "Unknown Messaging Entry", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/unknownMessagingEntryFBA.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", - PrepRequest: addValidSignature, + Label: "Unknown Messaging Entry", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/unknownMessagingEntryFBA.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", + PrepRequest: addValidSignature, }, { - Label: "Not JSON", - URL: "/c/fba/receive", - Data: "not JSON", - ExpectedStatus: 400, - ExpectedResponse: "Error", - PrepRequest: addValidSignature, + Label: "Not JSON", + URL: "/c/fba/receive", + Data: "not JSON", + ExpectedRespStatus: 400, + ExpectedRespBody: "Error", + PrepRequest: addValidSignature, }, { - Label: "Invalid URN", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/invalidURNFBA.json")), - ExpectedStatus: 400, - ExpectedResponse: "invalid facebook id", - PrepRequest: addValidSignature, + Label: "Invalid URN", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/invalidURNFBA.json")), + ExpectedRespStatus: 400, + ExpectedRespBody: "invalid facebook id", + PrepRequest: addValidSignature, }, } @@ -257,8 +257,8 @@ var testCasesIG = []ChannelHandleTestCase{ Label: "Receive Message", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Hello World"), @@ -268,19 +268,19 @@ var testCasesIG = []ChannelHandleTestCase{ PrepRequest: addValidSignature, }, { - Label: "Receive Invalid Signature", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), - ExpectedStatus: 400, - ExpectedResponse: "invalid request signature", - PrepRequest: addInvalidSignature, + Label: "Receive Invalid Signature", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), + ExpectedRespStatus: 400, + ExpectedRespBody: "invalid request signature", + PrepRequest: addInvalidSignature, }, { Label: "No Duplicate Receive Message", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/duplicateMsgIG.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", ExpectedMsgText: Sp("Hello World"), ExpectedURN: "instagram:5678", ExpectedExternalID: "external_id", @@ -291,8 +291,8 @@ var testCasesIG = []ChannelHandleTestCase{ Label: "Receive Attachment", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/attachmentIG.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://image-url/foo.png"}, ExpectedURN: "instagram:5678", @@ -304,8 +304,8 @@ var testCasesIG = []ChannelHandleTestCase{ Label: "Receive Like Heart", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/like_heart.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", ExpectedMsgText: Sp(""), ExpectedURN: "instagram:5678", ExpectedExternalID: "external_id", @@ -313,96 +313,96 @@ var testCasesIG = []ChannelHandleTestCase{ PrepRequest: addValidSignature, }, { - Label: "Receive Icebreaker Get Started", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/icebreakerGetStarted.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", - ExpectedURN: "instagram:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedChannelEvent: courier.NewConversation, - ExpectedChannelEventExtra: map[string]interface{}{"title": "icebreaker question", "payload": "get_started"}, - PrepRequest: addValidSignature, + Label: "Receive Icebreaker Get Started", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/icebreakerGetStarted.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", + ExpectedURN: "instagram:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.NewConversation, + ExpectedEventExtra: map[string]interface{}{"title": "icebreaker question", "payload": "get_started"}, + PrepRequest: addValidSignature, }, { - Label: "Different Page", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/differentPageIG.json")), - ExpectedStatus: 200, - ExpectedResponse: `"data":[]`, - PrepRequest: addValidSignature, + Label: "Different Page", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/differentPageIG.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: `"data":[]`, + PrepRequest: addValidSignature, }, { - Label: "Echo", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/echoIG.json")), - ExpectedStatus: 200, - ExpectedResponse: `ignoring echo`, - PrepRequest: addValidSignature, + Label: "Echo", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/echoIG.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: `ignoring echo`, + PrepRequest: addValidSignature, }, { - Label: "No Entries", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/noEntriesIG.json")), - ExpectedStatus: 400, - ExpectedResponse: "no entries found", - PrepRequest: addValidSignature, + Label: "No Entries", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/noEntriesIG.json")), + ExpectedRespStatus: 400, + ExpectedRespBody: "no entries found", + PrepRequest: addValidSignature, }, { - Label: "Not Instagram", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/notInstagram.json")), - ExpectedStatus: 400, - ExpectedResponse: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notinstagram", - PrepRequest: addValidSignature, + Label: "Not Instagram", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/notInstagram.json")), + ExpectedRespStatus: 400, + ExpectedRespBody: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notinstagram", + PrepRequest: addValidSignature, }, { - Label: "No Messaging Entries", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/noMessagingEntriesIG.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", - PrepRequest: addValidSignature, + Label: "No Messaging Entries", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/noMessagingEntriesIG.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", + PrepRequest: addValidSignature, }, { - Label: "Unknown Messaging Entry", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/unknownMessagingEntryIG.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", - PrepRequest: addValidSignature, + Label: "Unknown Messaging Entry", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/unknownMessagingEntryIG.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", + PrepRequest: addValidSignature, }, { - Label: "Not JSON", - URL: "/c/ig/receive", - Data: "not JSON", - ExpectedStatus: 400, - ExpectedResponse: "Error", - PrepRequest: addValidSignature, + Label: "Not JSON", + URL: "/c/ig/receive", + Data: "not JSON", + ExpectedRespStatus: 400, + ExpectedRespBody: "Error", + PrepRequest: addValidSignature, }, { - Label: "Invalid URN", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/invalidURNIG.json")), - ExpectedStatus: 400, - ExpectedResponse: "invalid instagram id", - PrepRequest: addValidSignature, + Label: "Invalid URN", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/invalidURNIG.json")), + ExpectedRespStatus: 400, + ExpectedRespBody: "invalid instagram id", + PrepRequest: addValidSignature, }, { - Label: "Story Mention", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/storyMentionIG.json")), - ExpectedStatus: 200, - ExpectedResponse: `ignoring story_mention`, - PrepRequest: addValidSignature, + Label: "Story Mention", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/storyMentionIG.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: `ignoring story_mention`, + PrepRequest: addValidSignature, }, { - Label: "Message unsent", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/unsentMsgIG.json")), - ExpectedStatus: 200, - ExpectedResponse: `msg deleted`, - PrepRequest: addValidSignature, + Label: "Message unsent", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/unsentMsgIG.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: `msg deleted`, + PrepRequest: addValidSignature, }, } @@ -536,8 +536,8 @@ var testCasesWAC = []ChannelHandleTestCase{ Label: "Receive Message WAC", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/helloWAC.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Hello World"), @@ -550,8 +550,8 @@ var testCasesWAC = []ChannelHandleTestCase{ Label: "Receive Duplicate Valid Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/duplicateWAC.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Hello World"), @@ -564,8 +564,8 @@ var testCasesWAC = []ChannelHandleTestCase{ Label: "Receive Valid Voice Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/voiceWAC.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp(""), @@ -579,8 +579,8 @@ var testCasesWAC = []ChannelHandleTestCase{ Label: "Receive Valid Button Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/buttonWAC.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("No"), @@ -593,8 +593,8 @@ var testCasesWAC = []ChannelHandleTestCase{ Label: "Receive Valid Document Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/documentWAC.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("80skaraokesonglistartist"), @@ -608,8 +608,8 @@ var testCasesWAC = []ChannelHandleTestCase{ Label: "Receive Valid Image Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/imageWAC.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Check out my new phone!"), @@ -623,8 +623,8 @@ var testCasesWAC = []ChannelHandleTestCase{ Label: "Receive Valid Video Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/videoWAC.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Check out my new phone!"), @@ -638,8 +638,8 @@ var testCasesWAC = []ChannelHandleTestCase{ Label: "Receive Valid Audio Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/audioWAC.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Check out my new phone!"), @@ -653,8 +653,8 @@ var testCasesWAC = []ChannelHandleTestCase{ Label: "Receive Valid Location Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/locationWAC.json")), - ExpectedStatus: 200, - ExpectedResponse: `"type":"msg"`, + ExpectedRespStatus: 200, + ExpectedRespBody: `"type":"msg"`, ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: "whatsapp:5678", @@ -663,61 +663,61 @@ var testCasesWAC = []ChannelHandleTestCase{ PrepRequest: addValidSignature, }, { - Label: "Receive Invalid JSON", - URL: wacReceiveURL, - Data: "not json", - ExpectedStatus: 400, - ExpectedResponse: "unable to parse", - PrepRequest: addValidSignature, + Label: "Receive Invalid JSON", + URL: wacReceiveURL, + Data: "not json", + ExpectedRespStatus: 400, + ExpectedRespBody: "unable to parse", + PrepRequest: addValidSignature, }, { - Label: "Receive Invalid JSON", - URL: wacReceiveURL, - Data: string(test.ReadFile("./testdata/wac/invalidFrom.json")), - ExpectedStatus: 400, - ExpectedResponse: "invalid whatsapp id", - PrepRequest: addValidSignature, + Label: "Receive Invalid JSON", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/invalidFrom.json")), + ExpectedRespStatus: 400, + ExpectedRespBody: "invalid whatsapp id", + PrepRequest: addValidSignature, }, { - Label: "Receive Invalid JSON", - URL: wacReceiveURL, - Data: string(test.ReadFile("./testdata/wac/invalidTimestamp.json")), - ExpectedStatus: 400, - ExpectedResponse: "invalid timestamp", - PrepRequest: addValidSignature, + Label: "Receive Invalid JSON", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/invalidTimestamp.json")), + ExpectedRespStatus: 400, + ExpectedRespBody: "invalid timestamp", + PrepRequest: addValidSignature, }, { Label: "Receive Valid Status", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/validStatusWAC.json")), - ExpectedStatus: 200, - ExpectedResponse: `"type":"status"`, + ExpectedRespStatus: 200, + ExpectedRespBody: `"type":"status"`, ExpectedMsgStatus: "S", ExpectedExternalID: "external_id", PrepRequest: addValidSignature, }, { - Label: "Receive Invalid Status", - URL: wacReceiveURL, - Data: string(test.ReadFile("./testdata/wac/invalidStatusWAC.json")), - ExpectedStatus: 400, - ExpectedResponse: `"unknown status: in_orbit"`, - PrepRequest: addValidSignature, + Label: "Receive Invalid Status", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/invalidStatusWAC.json")), + ExpectedRespStatus: 400, + ExpectedRespBody: `"unknown status: in_orbit"`, + PrepRequest: addValidSignature, }, { - Label: "Receive Ignore Status", - URL: wacReceiveURL, - Data: string(test.ReadFile("./testdata/wac/ignoreStatusWAC.json")), - ExpectedStatus: 200, - ExpectedResponse: `"ignoring status: deleted"`, - PrepRequest: addValidSignature, + Label: "Receive Ignore Status", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/ignoreStatusWAC.json")), + ExpectedRespStatus: 200, + ExpectedRespBody: `"ignoring status: deleted"`, + PrepRequest: addValidSignature, }, { Label: "Receive Valid Interactive Button Reply Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/buttonReplyWAC.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Yes"), @@ -730,8 +730,8 @@ var testCasesWAC = []ChannelHandleTestCase{ Label: "Receive Valid Interactive List Reply Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/listReplyWAC.json")), - ExpectedStatus: 200, - ExpectedResponse: "Handled", + ExpectedRespStatus: 200, + ExpectedRespBody: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Yes"), @@ -807,34 +807,34 @@ func TestVerify(t *testing.T) { { Label: "Valid Secret", URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", - ExpectedStatus: 200, - ExpectedResponse: "yarchallenge", + ExpectedRespStatus: 200, + ExpectedRespBody: "yarchallenge", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, }, { - Label: "Verify No Mode", - URL: "/c/fba/receive", - ExpectedStatus: 400, - ExpectedResponse: "unknown request", + Label: "Verify No Mode", + URL: "/c/fba/receive", + ExpectedRespStatus: 400, + ExpectedRespBody: "unknown request", }, { - Label: "Verify No Secret", - URL: "/c/fba/receive?hub.mode=subscribe", - ExpectedStatus: 400, - ExpectedResponse: "token does not match secret", + Label: "Verify No Secret", + URL: "/c/fba/receive?hub.mode=subscribe", + ExpectedRespStatus: 400, + ExpectedRespBody: "token does not match secret", }, { - Label: "Invalid Secret", - URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=blah", - ExpectedStatus: 400, - ExpectedResponse: "token does not match secret", + Label: "Invalid Secret", + URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=blah", + ExpectedRespStatus: 400, + ExpectedRespBody: "token does not match secret", }, { - Label: "Valid Secret", - URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", - ExpectedStatus: 200, - ExpectedResponse: "yarchallenge", + Label: "Valid Secret", + URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", + ExpectedRespStatus: 200, + ExpectedRespBody: "yarchallenge", }, }) @@ -842,34 +842,34 @@ func TestVerify(t *testing.T) { { Label: "Valid Secret", URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", - ExpectedStatus: 200, - ExpectedResponse: "yarchallenge", + ExpectedRespStatus: 200, + ExpectedRespBody: "yarchallenge", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, }, { - Label: "Verify No Mode", - URL: "/c/ig/receive", - ExpectedStatus: 400, - ExpectedResponse: "unknown request", + Label: "Verify No Mode", + URL: "/c/ig/receive", + ExpectedRespStatus: 400, + ExpectedRespBody: "unknown request", }, { - Label: "Verify No Secret", - URL: "/c/ig/receive?hub.mode=subscribe", - ExpectedStatus: 400, - ExpectedResponse: "token does not match secret", + Label: "Verify No Secret", + URL: "/c/ig/receive?hub.mode=subscribe", + ExpectedRespStatus: 400, + ExpectedRespBody: "token does not match secret", }, { - Label: "Invalid Secret", - URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=blah", - ExpectedStatus: 400, - ExpectedResponse: "token does not match secret", + Label: "Invalid Secret", + URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=blah", + ExpectedRespStatus: 400, + ExpectedRespBody: "token does not match secret", }, { - Label: "Valid Secret", - URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", - ExpectedStatus: 200, - ExpectedResponse: "yarchallenge", + Label: "Valid Secret", + URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", + ExpectedRespStatus: 200, + ExpectedRespBody: "yarchallenge", }, }) } @@ -888,7 +888,7 @@ var SendTestCasesFBA = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -900,7 +900,7 @@ var SendTestCasesFBA = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"RESPONSE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -912,7 +912,7 @@ var SendTestCasesFBA = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"user_ref":"67890"},"message":{"text":"Simple Message"}}`, ExpectedContactURNs: map[string]bool{"facebook:12345": true, "ext:67890": true, "facebook:ref:67890": false}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -924,7 +924,7 @@ var SendTestCasesFBA = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"text":"Are you happy?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -937,7 +937,7 @@ var SendTestCasesFBA = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"ACCOUNT_UPDATE","recipient":{"id":"12345"},"message":{"text":"we exceed the max length?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -948,7 +948,7 @@ var SendTestCasesFBA = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"attachment":{"type":"image","payload":{"url":"https://foo.bar/image.jpg","is_reusable":true}}}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -962,7 +962,7 @@ var SendTestCasesFBA = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"CONFIRMED_EVENT_UPDATE","recipient":{"id":"12345"},"message":{"text":"This is some text.","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -973,7 +973,7 @@ var SendTestCasesFBA = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"attachment":{"type":"file","payload":{"url":"https://foo.bar/document.pdf","is_reusable":true}}}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -983,7 +983,7 @@ var SendTestCasesFBA = []ChannelSendTestCase{ MsgURN: "facebook:12345", MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, SendPrep: setSendURL, }, @@ -993,7 +993,7 @@ var SendTestCasesFBA = []ChannelSendTestCase{ MsgURN: "facebook:12345", MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 403, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } @@ -1006,7 +1006,7 @@ var SendTestCasesIG = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -1018,7 +1018,7 @@ var SendTestCasesIG = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"RESPONSE","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -1030,7 +1030,7 @@ var SendTestCasesIG = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"text":"Are you happy?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -1043,7 +1043,7 @@ var SendTestCasesIG = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"HUMAN_AGENT","recipient":{"id":"12345"},"message":{"text":"we exceed the max length?","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL, }, @@ -1054,7 +1054,7 @@ var SendTestCasesIG = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"attachment":{"type":"image","payload":{"url":"https://foo.bar/image.jpg","is_reusable":true}}}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL}, { @@ -1066,7 +1066,7 @@ var SendTestCasesIG = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"text":"This is some text.","quick_replies":[{"title":"Yes","payload":"Yes","content_type":"text"},{"title":"No","payload":"No","content_type":"text"}]}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL}, { @@ -1077,7 +1077,7 @@ var SendTestCasesIG = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"MESSAGE_TAG","tag":"HUMAN_AGENT","recipient":{"id":"12345"},"message":{"text":"Simple Message"}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL}, { @@ -1087,7 +1087,7 @@ var SendTestCasesIG = []ChannelSendTestCase{ MockResponseBody: `{"message_id": "mid.133"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_type":"UPDATE","recipient":{"id":"12345"},"message":{"attachment":{"type":"file","payload":{"url":"https://foo.bar/document.pdf","is_reusable":true}}}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "mid.133", SendPrep: setSendURL}, { @@ -1096,7 +1096,7 @@ var SendTestCasesIG = []ChannelSendTestCase{ MsgURN: "instagram:12345", MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, SendPrep: setSendURL, }, @@ -1106,7 +1106,7 @@ var SendTestCasesIG = []ChannelSendTestCase{ MsgURN: "instagram:12345", MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 403, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } @@ -1120,7 +1120,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockResponseStatus: 201, ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"Simple Message","preview_url":false}}`, ExpectedRequestPath: "/12345_ID/messages", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -1132,7 +1132,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockResponseStatus: 201, ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"☺","preview_url":false}}`, ExpectedRequestPath: "/12345_ID/messages", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -1153,7 +1153,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"audio caption","preview_url":false}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -1174,7 +1174,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"document caption","preview_url":false}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -1195,7 +1195,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"document caption","preview_url":false}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -1216,7 +1216,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"video caption","preview_url":false}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -1224,7 +1224,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ Label: "Template Send", MsgText: "templated message", MsgURN: "whatsapp:250788123123", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", MsgMetadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "language": "eng", "variables": ["Chef", "tomorrow"]}}`), MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, @@ -1240,7 +1240,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, MockResponseStatus: 200, ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"template","template":{"name":"revive_issue","language":{"policy":"deterministic","code":"en_US"},"components":[{"type":"body","sub_type":"","index":"","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -1259,7 +1259,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, MockResponseStatus: 201, ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -1271,7 +1271,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, MockResponseStatus: 201, ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -1293,7 +1293,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -1315,7 +1315,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -1327,7 +1327,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MockResponseStatus: 201, ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"Link Sending https://link.com","preview_url":true}}`, ExpectedRequestPath: "/12345_ID/messages", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, diff --git a/handlers/firebase/firebase_test.go b/handlers/firebase/firebase_test.go index c2c67d120..32236437f 100644 --- a/handlers/firebase/firebase_test.go +++ b/handlers/firebase/firebase_test.go @@ -48,8 +48,8 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive Valid Message", URL: receiveURL, Data: "from=12345&date=2017-01-01T08:50:00.000&fcm_token=token&name=fred&msg=hello+world", - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("hello world"), ExpectedURN: "fcm:12345", ExpectedDate: time.Date(2017, 1, 1, 8, 50, 0, 0, time.UTC), @@ -57,32 +57,32 @@ var testCases = []ChannelHandleTestCase{ ExpectedContactName: Sp("fred"), }, { - Label: "Receive Invalid Date", - URL: receiveURL, - Data: "from=12345&date=yo&fcm_token=token&name=fred&msg=hello+world", - ExpectedStatus: 400, - ExpectedResponse: "unable to parse date", + Label: "Receive Invalid Date", + URL: receiveURL, + Data: "from=12345&date=yo&fcm_token=token&name=fred&msg=hello+world", + ExpectedRespStatus: 400, + ExpectedRespBody: "unable to parse date", }, { - Label: "Receive Missing From", - URL: receiveURL, - Data: "date=2017-01-01T08:50:00.000&fcm_token=token&name=fred&msg=hello+world", - ExpectedStatus: 400, - ExpectedResponse: "field 'from' required", + Label: "Receive Missing From", + URL: receiveURL, + Data: "date=2017-01-01T08:50:00.000&fcm_token=token&name=fred&msg=hello+world", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'from' required", }, { - Label: "Receive Valid Register", - URL: registerURL, - Data: "urn=12345&fcm_token=token&name=fred", - ExpectedStatus: 200, - ExpectedResponse: "contact_uuid", + Label: "Receive Valid Register", + URL: registerURL, + Data: "urn=12345&fcm_token=token&name=fred", + ExpectedRespStatus: 200, + ExpectedRespBody: "contact_uuid", }, { - Label: "Receive Missing URN", - URL: registerURL, - Data: "fcm_token=token&name=fred", - ExpectedStatus: 400, - ExpectedResponse: "field 'urn' required", + Label: "Receive Missing URN", + URL: registerURL, + Data: "fcm_token=token&name=fred", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'urn' required", }, } @@ -109,7 +109,7 @@ var notificationSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "key=FCMKey"}, ExpectedRequestBody: `{"data":{"type":"rapidpro","title":"FCMTitle","message":"Simple Message","message_id":10,"session_status":""},"notification":{"title":"FCMTitle","body":"Simple Message"},"content_available":true,"to":"auth1","priority":"high"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "123456", SendPrep: setSendURL, }, @@ -125,7 +125,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "key=FCMKey"}, ExpectedRequestBody: `{"data":{"type":"rapidpro","title":"FCMTitle","message":"Simple Message","message_id":10,"session_status":""},"content_available":false,"to":"auth1","priority":"high"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "123456", SendPrep: setSendURL, }, @@ -138,7 +138,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "key=FCMKey"}, ExpectedRequestBody: `{"data":{"type":"rapidpro","title":"FCMTitle","message":"ate ac.","message_id":10,"session_status":""},"content_available":false,"to":"auth1","priority":"high"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "123456", SendPrep: setSendURL, }, @@ -153,7 +153,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "key=FCMKey"}, ExpectedRequestBody: `{"data":{"type":"rapidpro","title":"FCMTitle","message":"Simple Message\nhttps://foo.bar","message_id":10,"session_status":"","quick_replies":["yes","no"]},"content_available":false,"to":"auth1","priority":"high"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "123456", SendPrep: setSendURL, }, @@ -164,7 +164,7 @@ var sendTestCases = []ChannelSendTestCase{ MsgURNAuth: "auth1", MockResponseBody: `{ "success": 0 }`, MockResponseStatus: 200, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received non-1 value for success in response", "")}, SendPrep: setSendURL, }, @@ -175,7 +175,7 @@ var sendTestCases = []ChannelSendTestCase{ MsgURNAuth: "auth1", MockResponseBody: `{ "success": 1 }`, MockResponseStatus: 200, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get multicast_id from response", "")}, SendPrep: setSendURL, }, @@ -186,7 +186,7 @@ var sendTestCases = []ChannelSendTestCase{ MsgURNAuth: "auth1", MockResponseBody: `{ "success": 0 }`, MockResponseStatus: 500, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } diff --git a/handlers/freshchat/freshchat_test.go b/handlers/freshchat/freshchat_test.go index 30f1d04a1..b3d2ea16b 100644 --- a/handlers/freshchat/freshchat_test.go +++ b/handlers/freshchat/freshchat_test.go @@ -30,45 +30,45 @@ const ( var sigtestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid w Signature", - Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": validSignature}, - URL: receiveURL, - Data: validReceive, - ExpectedStatus: 200, - ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Test 2"), - ExpectedURN: "freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd", - ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC), + Label: "Receive Valid w Signature", + Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": validSignature}, + URL: receiveURL, + Data: validReceive, + ExpectedRespStatus: 200, + ExpectedRespBody: "Message Accepted", + ExpectedMsgText: Sp("Test 2"), + ExpectedURN: "freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd", + ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC), }, { - Label: "Bad Signature", - Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": invalidSignature}, - URL: receiveURL, - Data: validReceive, - ExpectedStatus: 400, - ExpectedResponse: `{"message":"Error","data":[{"type":"error","error":"unable to verify signature, crypto/rsa: verification error"}]}`, + Label: "Bad Signature", + Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": invalidSignature}, + URL: receiveURL, + Data: validReceive, + ExpectedRespStatus: 400, + ExpectedRespBody: `{"message":"Error","data":[{"type":"error","error":"unable to verify signature, crypto/rsa: verification error"}]}`, }, } var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid w Sig", - Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": validSignature}, - URL: receiveURL, - Data: validReceive, - ExpectedStatus: 200, - ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Test 2"), - ExpectedURN: "freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd", - ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC), + Label: "Receive Valid w Sig", + Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": validSignature}, + URL: receiveURL, + Data: validReceive, + ExpectedRespStatus: 200, + ExpectedRespBody: "Message Accepted", + ExpectedMsgText: Sp("Test 2"), + ExpectedURN: "freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd", + ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC), }, { - Label: "Bad JSON", - Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": invalidSignature}, - URL: receiveURL, - Data: "empty", - ExpectedStatus: 400, - ExpectedResponse: `{"message":"Error","data":[{"type":"error","error":"unable to parse request JSON: invalid character 'e' looking for beginning of value"}]}`, + Label: "Bad JSON", + Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": invalidSignature}, + URL: receiveURL, + Data: "empty", + ExpectedRespStatus: 400, + ExpectedRespBody: `{"message":"Error","data":[{"type":"error","error":"unable to parse request JSON: invalid character 'e' looking for beginning of value"}]}`, }, } @@ -94,7 +94,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Authorization": "Bearer enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ="}, ExpectedRequestBody: `{"messages":[{"message_parts":[{"text":{"content":"Simple Message ☺"}}],"actor_id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606","actor_type":"agent"}],"channel_id":"0534f78-b6e9-4f79-8853-11cedfc1f35b","users":[{"id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", SendPrep: setSendURL, }, @@ -107,7 +107,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Authorization": "Bearer enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ="}, ExpectedRequestBody: `{"messages":[{"message_parts":[{"text":{"content":"Simple Message ☺"}},{"image":{"url":"https://foo.bar/image.jpg"}}],"actor_id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606","actor_type":"agent"}],"channel_id":"0534f78-b6e9-4f79-8853-11cedfc1f35b","users":[{"id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", SendPrep: setSendURL, }, @@ -119,7 +119,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Authorization": "Bearer enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ="}, ExpectedRequestBody: `{"messages":[{"message_parts":[{"image":{"url":"https://foo.bar/image.jpg"}}],"actor_id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606","actor_type":"agent"}],"channel_id":"0534f78-b6e9-4f79-8853-11cedfc1f35b","users":[{"id":"c8fddfaf-622a-4a0e-b060-4f3ccbeab606"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", SendPrep: setSendURL, }, diff --git a/handlers/globe/globe_test.go b/handlers/globe/globe_test.go index 12233dc19..889b16b7c 100644 --- a/handlers/globe/globe_test.go +++ b/handlers/globe/globe_test.go @@ -111,49 +111,49 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: receiveURL, - Data: validMessage, - ExpectedStatus: 200, - ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("hello world"), - ExpectedURN: "tel:+639171234567", - ExpectedDate: time.Date(2013, 11, 22, 12, 12, 13, 0, time.UTC), + Label: "Receive Valid Message", + URL: receiveURL, + Data: validMessage, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("hello world"), + ExpectedURN: "tel:+639171234567", + ExpectedDate: time.Date(2013, 11, 22, 12, 12, 13, 0, time.UTC), }, { - Label: "No Messages", - URL: receiveURL, - Data: noMessages, - ExpectedStatus: 200, - ExpectedResponse: "Ignored", + Label: "No Messages", + URL: receiveURL, + Data: noMessages, + ExpectedRespStatus: 200, + ExpectedRespBody: "Ignored", }, { - Label: "Invalid URN", - URL: receiveURL, - Data: invalidURN, - ExpectedStatus: 400, - ExpectedResponse: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL, + Data: invalidURN, + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", }, { - Label: "Invalid Sender", - URL: receiveURL, - Data: invalidSender, - ExpectedStatus: 400, - ExpectedResponse: "invalid 'senderAddress' parameter", + Label: "Invalid Sender", + URL: receiveURL, + Data: invalidSender, + ExpectedRespStatus: 400, + ExpectedRespBody: "invalid 'senderAddress' parameter", }, { - Label: "Invalid Date", - URL: receiveURL, - Data: invalidDate, - ExpectedStatus: 400, - ExpectedResponse: "parsing time", + Label: "Invalid Date", + URL: receiveURL, + Data: invalidDate, + ExpectedRespStatus: 400, + ExpectedRespBody: "parsing time", }, { - Label: "Invalid JSON", - URL: receiveURL, - Data: `notjson`, - ExpectedStatus: 400, - ExpectedResponse: "unable to parse request JSON", + Label: "Invalid JSON", + URL: receiveURL, + Data: `notjson`, + ExpectedRespStatus: 400, + ExpectedRespBody: "unable to parse request JSON", }, } @@ -178,7 +178,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, ExpectedRequestBody: `{"address":"250788383383","message":"Simple Message","passphrase":"opensesame","app_id":"12345","app_secret":"mysecret"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -188,7 +188,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, ExpectedRequestBody: `{"address":"250788383383","message":"☺","passphrase":"opensesame","app_id":"12345","app_secret":"mysecret"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -199,7 +199,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, ExpectedRequestBody: `{"address":"250788383383","message":"My pic!\nhttps://foo.bar/image.jpg","passphrase":"opensesame","app_id":"12345","app_secret":"mysecret"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -208,7 +208,7 @@ var sendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `[{"Response": "101"}]`, MockResponseStatus: 403, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } diff --git a/handlers/highconnection/highconnection_test.go b/handlers/highconnection/highconnection_test.go index 49f4953ae..6d2b374db 100644 --- a/handlers/highconnection/highconnection_test.go +++ b/handlers/highconnection/highconnection_test.go @@ -27,20 +27,20 @@ var ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Accepted", + Label: "Receive Valid Message", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Hello World"), ExpectedURN: "tel:+33610346460", ExpectedDate: time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC), }, { - Label: "Receive Valid Message with accents", URL: receiveURL, Data: validAccentReceive, ExpectedStatus: 200, ExpectedResponse: "Accepted", + Label: "Receive Valid Message with accents", URL: receiveURL, Data: validAccentReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("je suis très satisfait "), ExpectedURN: "tel:+33610346460", ExpectedDate: time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC), }, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Receive Missing Params", URL: receiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: "validation for 'From' failed"}, - {Label: "Receive Invalid Date", URL: receiveURL, Data: invalidDateReceive, ExpectedStatus: 400, ExpectedResponse: "cannot parse"}, - {Label: "Status Missing Params", URL: statusURL, ExpectedStatus: 400, ExpectedResponse: "validation for 'Status' failed"}, - {Label: "Status Delivered", URL: validStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, + {Label: "Receive Missing Params", URL: receiveURL, Data: " ", ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'From' failed"}, + {Label: "Receive Invalid Date", URL: receiveURL, Data: invalidDateReceive, ExpectedRespStatus: 400, ExpectedRespBody: "cannot parse"}, + {Label: "Status Missing Params", URL: statusURL, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'Status' failed"}, + {Label: "Status Delivered", URL: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`}, } func TestHandler(t *testing.T) { @@ -58,10 +58,10 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", - MsgText: "Simple Message", - MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + ExpectedMsgStatus: "W", + MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, ExpectedURLParams: map[string]string{ "accountid": "Username", "password": "Password", @@ -76,9 +76,9 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Plain Send without flow", - MsgText: "Simple Message", - MsgURN: "tel:+250788383383", - ExpectedStatus: "W", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + ExpectedMsgStatus: "W", ExpectedURLParams: map[string]string{ "accountid": "Username", "password": "Password", @@ -93,10 +93,10 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Unicode Send", - MsgText: "☺", - MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, + MsgText: "☺", + MsgURN: "tel:+250788383383", + ExpectedMsgStatus: "W", + MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, ExpectedURLParams: map[string]string{ "accountid": "Username", "password": "Password", @@ -111,10 +111,10 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Long Send", - MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + ExpectedMsgStatus: "W", + MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, ExpectedURLParams: map[string]string{ "accountid": "Username", "password": "Password", @@ -129,11 +129,11 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, SendPrep: setSendURL}, {Label: "Send Attachement", - MsgText: "My pic!", - MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, + MsgText: "My pic!", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MsgURN: "tel:+250788383383", + ExpectedMsgStatus: "W", + MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, ExpectedURLParams: map[string]string{ "accountid": "Username", "password": "Password", @@ -150,7 +150,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Error Sending", MsgText: "Error Sending", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", + ExpectedMsgStatus: "E", MockResponseStatus: 403, SendPrep: setSendURL}, } diff --git a/handlers/hormuud/hormuud_test.go b/handlers/hormuud/hormuud_test.go index 0a91322b2..561c8eb2e 100644 --- a/handlers/hormuud/hormuud_test.go +++ b/handlers/hormuud/hormuud_test.go @@ -26,12 +26,12 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp(""), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'sender' required"}, - {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "field 'sender' required"}, + {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, // {Label: "Status No Params", URL: statusNoParams, Status: 400, Response: "field 'status' required"}, // {Label: "Status Invalid Status", URL: statusInvalidStatus, Status: 400, Response: "unknown status '66', must be one of 1,2,4,8,16"}, // {Label: "Status Valid", URL: statusValid, Status: 200, Response: `"status":"S"`}, @@ -49,34 +49,34 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var sendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", ExpectedExternalID: "msg1", + ExpectedMsgStatus: "W", ExpectedExternalID: "msg1", MockResponseBody: `{"ResCode": "res", "ResMsg": "msg", "Data": { "MessageID": "msg1", "Description": "accepted" } }`, MockResponseStatus: 200, ExpectedRequestBody: `{"mobile":"250788383383","message":"Simple Message","senderid":"2020","mType":-1,"eType":-1,"UDH":""}`, SendPrep: setSendURL}, {Label: "Unicode Send", MsgText: "☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", ExpectedExternalID: "msg1", + ExpectedMsgStatus: "W", ExpectedExternalID: "msg1", MockResponseBody: `{"ResCode": "res", "ResMsg": "msg", "Data": { "MessageID": "msg1", "Description": "accepted" } }`, MockResponseStatus: 200, ExpectedRequestBody: `{"mobile":"250788383383","message":"☺","senderid":"2020","mType":-1,"eType":-1,"UDH":""}`, SendPrep: setSendURL}, {Label: "Send Attachment", MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", ExpectedExternalID: "msg1", + ExpectedMsgStatus: "W", ExpectedExternalID: "msg1", MockResponseBody: `{"ResCode": "res", "ResMsg": "msg", "Data": { "MessageID": "msg1", "Description": "accepted" } }`, MockResponseStatus: 200, ExpectedRequestBody: `{"mobile":"250788383383","message":"My pic!\nhttps://foo.bar/image.jpg","senderid":"2020","mType":-1,"eType":-1,"UDH":""}`, SendPrep: setSendURL}, {Label: "Error Sending", MsgText: "Error Sending", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `[{"Response": "101"}]`, MockResponseStatus: 403, + ExpectedMsgStatus: "E", + MockResponseBody: `[{"Response": "101"}]`, MockResponseStatus: 403, SendPrep: setSendURL}, } var tokenTestCases = []ChannelSendTestCase{ {Label: "Plain Send", MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - SendPrep: setSendURL}, + ExpectedMsgStatus: "E", + SendPrep: setSendURL}, } func TestSending(t *testing.T) { diff --git a/handlers/i2sms/i2sms_test.go b/handlers/i2sms/i2sms_test.go index b82194ceb..949b4b0de 100644 --- a/handlers/i2sms/i2sms_test.go +++ b/handlers/i2sms/i2sms_test.go @@ -19,20 +19,20 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: "message=Msg&mobile=254791541111", - ExpectedStatus: 200, - ExpectedResponse: "", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+254791541111", + Label: "Receive Valid", + URL: receiveURL, + Data: "message=Msg&mobile=254791541111", + ExpectedRespStatus: 200, + ExpectedRespBody: "", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+254791541111", }, { - Label: "Receive Missing Number", - URL: receiveURL, - Data: "message=Msg", - ExpectedStatus: 400, - ExpectedResponse: "required field 'mobile'", + Label: "Receive Missing Number", + URL: receiveURL, + Data: "message=Msg", + ExpectedRespStatus: 400, + ExpectedRespBody: "required field 'mobile'", }, } @@ -62,7 +62,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "message": "Simple Message ☺\nhttps://foo.bar/image.jpg", "channel": "hash123", }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "5b8fc97d58795484819426", SendPrep: setSendURL, }, @@ -72,7 +72,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `not json`, MockResponseStatus: 200, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("invalid character 'o' in literal null (expecting 'u')", "")}, SendPrep: setSendURL, }, @@ -82,7 +82,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `{"result":{}, "error_code": "10", "error_desc": "Failed"}`, MockResponseStatus: 200, - ExpectedStatus: "F", + ExpectedMsgStatus: "F", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid response code: 10", "")}, SendPrep: setSendURL, }, @@ -92,7 +92,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `Bad Gateway`, MockResponseStatus: 501, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } diff --git a/handlers/infobip/infobip_test.go b/handlers/infobip/infobip_test.go index b43131ea7..c3f5bd674 100644 --- a/handlers/infobip/infobip_test.go +++ b/handlers/infobip/infobip_test.go @@ -191,19 +191,19 @@ var invalidStatus = `{ }` var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message", URL: receiveURL, Data: helloMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("QUIZ Correct answer is Paris"), ExpectedURN: "tel:+385916242493", ExpectedExternalID: "817790313235066447", ExpectedDate: time.Date(2016, 10, 06, 9, 28, 39, 220000000, time.FixedZone("", 0))}, - {Label: "Receive missing results key", URL: receiveURL, Data: missingResults, ExpectedStatus: 400, ExpectedResponse: "validation for 'Results' failed"}, - {Label: "Receive missing text key", URL: receiveURL, Data: missingText, ExpectedStatus: 200, ExpectedResponse: "ignoring request, no message"}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Status report invalid JSON", URL: statusURL, Data: invalidJSONStatus, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, - {Label: "Status report missing results key", URL: statusURL, Data: statusMissingResultsKey, ExpectedStatus: 400, ExpectedResponse: "Field validation for 'Results' failed"}, - {Label: "Status delivered", URL: statusURL, Data: validStatusDelivered, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`}, - {Label: "Status rejected", URL: statusURL, Data: validStatusRejected, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`}, - {Label: "Status undeliverable", URL: statusURL, Data: validStatusUndeliverable, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`}, - {Label: "Status pending", URL: statusURL, Data: validStatusPending, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, - {Label: "Status expired", URL: statusURL, Data: validStatusExpired, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, - {Label: "Status group name unexpected", URL: statusURL, Data: invalidStatus, ExpectedStatus: 400, ExpectedResponse: `unknown status 'UNEXPECTED'`}, + {Label: "Receive missing results key", URL: receiveURL, Data: missingResults, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'Results' failed"}, + {Label: "Receive missing text key", URL: receiveURL, Data: missingText, ExpectedRespStatus: 200, ExpectedRespBody: "ignoring request, no message"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, + {Label: "Status report invalid JSON", URL: statusURL, Data: invalidJSONStatus, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, + {Label: "Status report missing results key", URL: statusURL, Data: statusMissingResultsKey, ExpectedRespStatus: 400, ExpectedRespBody: "Field validation for 'Results' failed"}, + {Label: "Status delivered", URL: statusURL, Data: validStatusDelivered, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`}, + {Label: "Status rejected", URL: statusURL, Data: validStatusRejected, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`}, + {Label: "Status undeliverable", URL: statusURL, Data: validStatusUndeliverable, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`}, + {Label: "Status pending", URL: statusURL, Data: validStatusPending, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`}, + {Label: "Status expired", URL: statusURL, Data: validStatusExpired, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`}, + {Label: "Status group name unexpected", URL: statusURL, Data: invalidStatus, ExpectedRespStatus: 400, ExpectedRespBody: `unknown status 'UNEXPECTED'`}, } func TestHandler(t *testing.T) { @@ -224,7 +224,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Label: "Plain Send", MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "12345", MockResponseBody: `{"messages":[{"status":{"groupId": 1}, "messageId": "12345"}}`, MockResponseStatus: 200, @@ -248,7 +248,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"☺","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -264,7 +264,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"My pic!\nhttps://foo.bar/image.jpg","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -279,7 +279,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Error Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -294,7 +294,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Simple Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error status: '2'", "")}, SendPrep: setSendURL, }, @@ -313,7 +313,7 @@ var transSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Simple Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered","transliteration":"COLOMBIAN"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "12345", SendPrep: setSendURL, }, diff --git a/handlers/jasmin/jasmin_test.go b/handlers/jasmin/jasmin_test.go index fbcdb9102..5d40d233a 100644 --- a/handlers/jasmin/jasmin_test.go +++ b/handlers/jasmin/jasmin_test.go @@ -27,20 +27,20 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "ACK/Jasmin", + {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedRespStatus: 200, ExpectedRespBody: "ACK/Jasmin", ExpectedMsgText: Sp("événement"), ExpectedURN: "tel:+2349067554729", ExpectedExternalID: "1001"}, - {Label: "Receive Missing To", URL: receiveURL, Data: receiveMissingTo, ExpectedStatus: 400, - ExpectedResponse: "field 'to' required"}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, - ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Status Delivered", URL: statusURL, Data: statusDelivered, ExpectedStatus: 200, ExpectedResponse: "ACK/Jasmin", + {Label: "Receive Missing To", URL: receiveURL, Data: receiveMissingTo, ExpectedRespStatus: 400, + ExpectedRespBody: "field 'to' required"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number"}, + {Label: "Status Delivered", URL: statusURL, Data: statusDelivered, ExpectedRespStatus: 200, ExpectedRespBody: "ACK/Jasmin", ExpectedMsgStatus: "D", ExpectedExternalID: "external1"}, - {Label: "Status Failed", URL: statusURL, Data: statusFailed, ExpectedStatus: 200, ExpectedResponse: "ACK/Jasmin", + {Label: "Status Failed", URL: statusURL, Data: statusFailed, ExpectedRespStatus: 200, ExpectedRespBody: "ACK/Jasmin", ExpectedMsgStatus: "F", ExpectedExternalID: "external1"}, - {Label: "Status Missing", URL: statusURL, ExpectedStatus: 400, Data: "nothing", - ExpectedResponse: "field 'id' required"}, - {Label: "Status Unknown", URL: statusURL, ExpectedStatus: 400, Data: statusUnknown, - ExpectedResponse: "must have either dlvrd or err set to 1"}, + {Label: "Status Missing", URL: statusURL, ExpectedRespStatus: 400, Data: "nothing", + ExpectedRespBody: "field 'id' required"}, + {Label: "Status Unknown", URL: statusURL, ExpectedRespStatus: 400, Data: statusUnknown, + ExpectedRespBody: "must have either dlvrd or err set to 1"}, } func TestHandler(t *testing.T) { @@ -59,34 +59,34 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: `Success "External ID1"`, MockResponseStatus: 200, ExpectedExternalID: "External ID1", + ExpectedMsgStatus: "W", + MockResponseBody: `Success "External ID1"`, MockResponseStatus: 200, ExpectedExternalID: "External ID1", ExpectedURLParams: map[string]string{"content": "Simple Message", "to": "250788383383", "coding": "0", "dlr-level": "2", "dlr": "yes", "dlr-method": http.MethodPost, "username": "Username", "password": "Password", "dlr-url": "https://localhost/c/js/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status"}, SendPrep: setSendURL}, {Label: "Unicode Send", - MsgText: "☺", - ExpectedStatus: "W", - MockResponseBody: `Success "External ID1"`, MockResponseStatus: 200, + MsgText: "☺", + ExpectedMsgStatus: "W", + MockResponseBody: `Success "External ID1"`, MockResponseStatus: 200, ExpectedURLParams: map[string]string{"content": "?"}, SendPrep: setSendURL}, {Label: "Smart Encoding", MsgText: "Fancy “Smart” Quotes", MsgURN: "tel:+250788383383", MsgHighPriority: false, - ExpectedStatus: "W", - MockResponseBody: `Success "External ID1"`, MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: `Success "External ID1"`, MockResponseStatus: 200, ExpectedURLParams: map[string]string{"content": `Fancy "Smart" Quotes`}, SendPrep: setSendURL}, {Label: "Send Attachment", MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgHighPriority: true, MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: `Success "External ID1"`, MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: `Success "External ID1"`, MockResponseStatus: 200, ExpectedURLParams: map[string]string{"content": "My pic!\nhttps://foo.bar/image.jpg"}, SendPrep: setSendURL}, {Label: "Error Sending", MsgText: "Error Message", MsgURN: "tel:+250788383383", MsgHighPriority: false, - ExpectedStatus: "E", - MockResponseBody: "Failed Sending", MockResponseStatus: 401, + ExpectedMsgStatus: "E", + MockResponseBody: "Failed Sending", MockResponseStatus: 401, ExpectedURLParams: map[string]string{"content": `Error Message`}, SendPrep: setSendURL}, } diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index 57b8ade4a..be641c606 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -146,28 +146,28 @@ func addInvalidSignature(r *http.Request) { } var testCases = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Simple Message"), ExpectedURN: "jiochat:1234", ExpectedExternalID: "123456", ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "invalid jiochat id"}, - {Label: "Missing params", URL: receiveURL, Data: missingParamsRequired, ExpectedStatus: 400, ExpectedResponse: "Error:Field validation"}, - {Label: "Missing params Event or MsgId", URL: receiveURL, Data: missingParams, ExpectedStatus: 400, ExpectedResponse: "missing parameters, must have either 'MsgId' or 'Event'"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "invalid jiochat id"}, + {Label: "Missing params", URL: receiveURL, Data: missingParamsRequired, ExpectedRespStatus: 400, ExpectedRespBody: "Error:Field validation"}, + {Label: "Missing params Event or MsgId", URL: receiveURL, Data: missingParams, ExpectedRespStatus: 400, ExpectedRespBody: "missing parameters, must have either 'MsgId' or 'Event'"}, - {Label: "Receive Image", URL: receiveURL, Data: imageMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Image", URL: receiveURL, Data: imageMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp(""), ExpectedURN: "jiochat:1234", ExpectedExternalID: "123456", ExpectedAttachments: []string{"https://channels.jiochat.com/media/download.action?media_id=12"}, ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, - {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedStatus: 200, ExpectedResponse: "Event Accepted", - ExpectedChannelEvent: courier.NewConversation, ExpectedURN: "jiochat:1234"}, + {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedRespStatus: 200, ExpectedRespBody: "Event Accepted", + ExpectedEvent: courier.NewConversation, ExpectedURN: "jiochat:1234"}, - {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, ExpectedStatus: 200, ExpectedResponse: "unknown event"}, + {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, ExpectedRespStatus: 200, ExpectedRespBody: "unknown event"}, - {Label: "Verify URL", URL: verifyURL, ExpectedStatus: 200, ExpectedResponse: "SUCCESS", + {Label: "Verify URL", URL: verifyURL, ExpectedRespStatus: 200, ExpectedRespBody: "SUCCESS", PrepRequest: addValidSignature}, - {Label: "Verify URL Invalid signature", URL: verifyURL, ExpectedStatus: 400, ExpectedResponse: "unknown request", + {Label: "Verify URL Invalid signature", URL: verifyURL, ExpectedRespStatus: 400, ExpectedRespBody: "unknown request", PrepRequest: addInvalidSignature}, } @@ -195,12 +195,12 @@ func TestFetchAccessToken(t *testing.T) { fetchTimeout = time.Millisecond RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ - {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted"}, + {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted"}, - {Label: "Verify URL", URL: verifyURL, ExpectedStatus: 200, ExpectedResponse: "SUCCESS", + {Label: "Verify URL", URL: verifyURL, ExpectedRespStatus: 200, ExpectedRespBody: "SUCCESS", PrepRequest: addValidSignature}, - {Label: "Verify URL Invalid signature", URL: verifyURL, ExpectedStatus: 400, ExpectedResponse: "unknown request", + {Label: "Verify URL Invalid signature", URL: verifyURL, ExpectedRespStatus: 400, ExpectedRespBody: "unknown request", PrepRequest: addInvalidSignature}, }) @@ -337,7 +337,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Bearer ACCESS_TOKEN", }, ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"Simple Message ☺"}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", SendPrep: setSendURL, }, @@ -352,7 +352,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Bearer ACCESS_TOKEN", }, ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"I need to keep adding more things to make it work"}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", SendPrep: setSendURL, }, @@ -368,7 +368,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Bearer ACCESS_TOKEN", }, ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"My pic!\nhttps://foo.bar/image.jpg"}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", SendPrep: setSendURL, }, @@ -377,7 +377,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "Error Message", MsgURN: "jiochat:12345", MockResponseStatus: 401, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } diff --git a/handlers/junebug/junebug_test.go b/handlers/junebug/junebug_test.go index 132ca447e..2077c4d4b 100644 --- a/handlers/junebug/junebug_test.go +++ b/handlers/junebug/junebug_test.go @@ -93,44 +93,44 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: inboundURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message", URL: inboundURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("hello world"), ExpectedURN: "tel:+250788383383", ExpectedDate: time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC)}, {Label: "Invalid URN", URL: inboundURL, Data: invalidURN, - ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, {Label: "Invalid Timestamp", URL: inboundURL, Data: invalidTimestamp, - ExpectedStatus: 400, ExpectedResponse: "unable to parse date"}, + ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse date"}, {Label: "Missing Message ID", URL: inboundURL, Data: missingMessageID, - ExpectedStatus: 400, ExpectedResponse: "'MessageID' failed on the 'required'"}, + ExpectedRespStatus: 400, ExpectedRespBody: "'MessageID' failed on the 'required'"}, - {Label: "Receive Pending Event", URL: eventURL, Data: pendingEvent, ExpectedStatus: 200, ExpectedResponse: "Ignored"}, - {Label: "Receive Sent Event", URL: eventURL, Data: sentEvent, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Pending Event", URL: eventURL, Data: pendingEvent, ExpectedRespStatus: 200, ExpectedRespBody: "Ignored"}, + {Label: "Receive Sent Event", URL: eventURL, Data: sentEvent, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedExternalID: "xx12345", ExpectedMsgStatus: "S"}, - {Label: "Receive Delivered Event", URL: eventURL, Data: deliveredEvent, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Delivered Event", URL: eventURL, Data: deliveredEvent, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedExternalID: "xx12345", ExpectedMsgStatus: "D"}, - {Label: "Receive Failed Event", URL: eventURL, Data: failedEvent, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Failed Event", URL: eventURL, Data: failedEvent, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedExternalID: "xx12345", ExpectedMsgStatus: "F"}, - {Label: "Receive Unknown Event", URL: eventURL, Data: unknownEvent, ExpectedStatus: 200, ExpectedResponse: "Ignored"}, + {Label: "Receive Unknown Event", URL: eventURL, Data: unknownEvent, ExpectedRespStatus: 200, ExpectedRespBody: "Ignored"}, - {Label: "Receive Invalid JSON", URL: eventURL, Data: "not json", ExpectedStatus: 400, ExpectedResponse: "Error"}, - {Label: "Receive Missing Event Type", URL: eventURL, Data: missingEventType, ExpectedStatus: 400, ExpectedResponse: "Error"}, + {Label: "Receive Invalid JSON", URL: eventURL, Data: "not json", ExpectedRespStatus: 400, ExpectedRespBody: "Error"}, + {Label: "Receive Missing Event Type", URL: eventURL, Data: missingEventType, ExpectedRespStatus: 400, ExpectedRespBody: "Error"}, } var authenticatedTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: inboundURL, Data: validMsg, Headers: map[string]string{"Authorization": "Token sesame"}, - ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("hello world"), ExpectedURN: "tel:+250788383383", ExpectedDate: time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC)}, {Label: "Invalid Incoming Authorization", URL: inboundURL, Data: validMsg, Headers: map[string]string{"Authorization": "Token foo"}, - ExpectedStatus: 401, ExpectedResponse: "Unauthorized"}, + ExpectedRespStatus: 401, ExpectedRespBody: "Unauthorized"}, {Label: "Receive Sent Event", URL: eventURL, Data: sentEvent, Headers: map[string]string{"Authorization": "Token sesame"}, - ExpectedStatus: 200, ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedExternalID: "xx12345", ExpectedMsgStatus: "S"}, {Label: "Invalid Incoming Authorization", URL: eventURL, Data: sentEvent, Headers: map[string]string{"Authorization": "Token foo"}, - ExpectedStatus: 401, ExpectedResponse: "Unauthorized"}, + ExpectedRespStatus: 401, ExpectedRespBody: "Unauthorized"}, } func TestHandler(t *testing.T) { @@ -155,7 +155,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "Basic dXNlcjE6cGFzczE="}, ExpectedRequestBody: `{"event_url":"https://localhost/c/jn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/event","content":"Simple Message","from":"2020","to":"+250788383383"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "externalID", SendPrep: setSendURL, }, @@ -167,7 +167,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"result":{"message_id":"externalID"}}`, MockResponseStatus: 200, ExpectedRequestBody: `{"event_url":"https://localhost/c/jn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/event","content":"My pic!\nhttps://foo.bar/image.jpg","from":"2020","to":"+250788383383"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "externalID", SendPrep: setSendURL, }, @@ -177,7 +177,7 @@ var sendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseStatus: 200, MockResponseBody: "not json", - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get result.message_id from body", "")}, SendPrep: setSendURL, }, @@ -187,7 +187,7 @@ var sendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseStatus: 200, MockResponseBody: "{}", - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get result.message_id from body", "")}, SendPrep: setSendURL, }, @@ -196,7 +196,7 @@ var sendTestCases = []ChannelSendTestCase{ MsgText: "Error Sending", MsgURN: "tel:+250788383383", MockResponseStatus: 403, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } @@ -210,7 +210,7 @@ var authenticatedSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "Basic dXNlcjE6cGFzczE="}, ExpectedRequestBody: `{"event_url":"https://localhost/c/jn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/event","content":"Simple Message","from":"2020","to":"+250788383383","event_auth_token":"sesame"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "externalID", SendPrep: setSendURL, }, diff --git a/handlers/kaleyra/kaleyra_test.go b/handlers/kaleyra/kaleyra_test.go index 78dfdfabd..e34d3f19e 100644 --- a/handlers/kaleyra/kaleyra_test.go +++ b/handlers/kaleyra/kaleyra_test.go @@ -35,8 +35,8 @@ var testCases = []ChannelHandleTestCase{ ExpectedURN: "whatsapp:14133881111", ExpectedMsgText: Sp("Hello World"), ExpectedAttachments: []string{}, - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", }, { Label: "Receive Media", @@ -45,63 +45,63 @@ var testCases = []ChannelHandleTestCase{ ExpectedURN: "whatsapp:14133881111", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://link.to/image.jpg"}, - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", }, { - Label: "Receive Empty", - URL: receiveMsgURL + "?created_at=1603914166&type=text&from=14133881111&name=John%20Cruz", - ExpectedStatus: 400, - ExpectedResponse: "no text or media", + Label: "Receive Empty", + URL: receiveMsgURL + "?created_at=1603914166&type=text&from=14133881111&name=John%20Cruz", + ExpectedRespStatus: 400, + ExpectedRespBody: "no text or media", }, { Label: "Receive Invalid CreatedAt", URL: receiveMsgURL + "?created_at=nottimestamp&type=text&from=14133881111&name=John%20Cruz&body=Hi", ExpectedContactName: Sp("John Cruz"), - ExpectedStatus: 400, - ExpectedResponse: "invalid created_at", + ExpectedRespStatus: 400, + ExpectedRespBody: "invalid created_at", }, { - Label: "Receive Invalid Type", - URL: receiveMsgURL + "?created_at=1603914166&type=sticker&from=14133881111&name=John%20Cruz", - ExpectedStatus: 200, - ExpectedResponse: "unknown message type", + Label: "Receive Invalid Type", + URL: receiveMsgURL + "?created_at=1603914166&type=sticker&from=14133881111&name=John%20Cruz", + ExpectedRespStatus: 200, + ExpectedRespBody: "unknown message type", }, { Label: "Receive Invalid From", URL: receiveMsgURL + "?created_at=1603914166&type=text&from=notnumber&name=John%20Cruz&body=Hi", ExpectedContactName: Sp("John Cruz"), - ExpectedStatus: 400, - ExpectedResponse: "invalid whatsapp id", + ExpectedRespStatus: 400, + ExpectedRespBody: "invalid whatsapp id", }, { - Label: "Receive Blank From", - URL: receiveMsgURL, - ExpectedStatus: 400, - ExpectedResponse: "field 'from' required", + Label: "Receive Blank From", + URL: receiveMsgURL, + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'from' required", }, { Label: "Receive Valid Status", URL: receiveStatusURL + "?id=58f86fab-85c5-4f7c-9b68-9c323248afc4%3A0&status=read", ExpectedExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", ExpectedMsgStatus: "D", - ExpectedStatus: 200, - ExpectedResponse: `"type":"status"`, + ExpectedRespStatus: 200, + ExpectedRespBody: `"type":"status"`, }, { Label: "Receive Invalid Status", URL: receiveStatusURL + "?id=58f86fab-85c5-4f7c-9b68-9c323248afc4%3A0&status=deleted", ExpectedExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", ExpectedMsgStatus: "D", - ExpectedStatus: 200, - ExpectedResponse: "unknown status", + ExpectedRespStatus: 200, + ExpectedRespBody: "unknown status", }, { Label: "Receive Blank status", URL: receiveStatusURL, ExpectedExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", - ExpectedStatus: 400, - ExpectedResponse: "field 'status' required", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'status' required", }, } @@ -122,7 +122,7 @@ var sendTestCases = []ChannelSendTestCase{ Label: "Plain Send", MsgText: "Simple Message", MsgURN: "whatsapp:14133881111", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", ExpectedRequestPath: "/v1/SID/messages", ExpectedHeaders: map[string]string{"Content-type": "application/x-www-form-urlencoded"}, @@ -135,7 +135,7 @@ var sendTestCases = []ChannelSendTestCase{ Label: "Unicode Send", MsgText: "☺", MsgURN: "whatsapp:14133881111", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", ExpectedRequestPath: "/v1/SID/messages", ExpectedHeaders: map[string]string{"Content-type": "application/x-www-form-urlencoded"}, @@ -148,7 +148,7 @@ var sendTestCases = []ChannelSendTestCase{ Label: "URL Send", MsgText: "foo https://foo.bar bar", MsgURN: "whatsapp:14133881111", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", ExpectedRequestPath: "/v1/SID/messages", ExpectedHeaders: map[string]string{"Content-type": "application/x-www-form-urlencoded"}, @@ -161,7 +161,7 @@ var sendTestCases = []ChannelSendTestCase{ Label: "Plain Send Error", MsgText: "Error", MsgURN: "whatsapp:14133881112", - ExpectedStatus: "F", + ExpectedMsgStatus: "F", ExpectedRequestPath: "/v1/SID/messages", ExpectedHeaders: map[string]string{"Content-type": "application/x-www-form-urlencoded"}, ExpectedRequestBody: "api-key=123456&body=Error&callback_url=https%3A%2F%2Flocalhost%2Fc%2Fkwa%2F8eb23e93-5ecb-45ba-b726-3b064e0c568c%2Fstatus&channel=WhatsApp&from=250788383383&to=14133881112&type=text", @@ -174,7 +174,7 @@ var sendTestCases = []ChannelSendTestCase{ MsgText: "Medias", MsgAttachments: []string{"image/jpg:https://foo.bar/image.jpg", "image/png:https://foo.bar/video.mp4"}, MsgURN: "whatsapp:14133881111", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "f75fbe1e-a0c0-4923-96e8-5043aa617b2b:0", MockResponses: map[MockedRequest]*httpx.MockResponse{ { @@ -191,11 +191,11 @@ var sendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL, }, { - Label: "Media Send Error", - MsgText: "Medias", - MsgAttachments: []string{"image/jpg:https://foo.bar/image.jpg", "image/png:https://foo.bar/video.wmv"}, - MsgURN: "whatsapp:14133881111", - ExpectedStatus: "F", + Label: "Media Send Error", + MsgText: "Medias", + MsgAttachments: []string{"image/jpg:https://foo.bar/image.jpg", "image/png:https://foo.bar/video.wmv"}, + MsgURN: "whatsapp:14133881111", + ExpectedMsgStatus: "F", MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", diff --git a/handlers/kannel/kannel_test.go b/handlers/kannel/kannel_test.go index f3b7384e1..674120ffe 100644 --- a/handlers/kannel/kannel_test.go +++ b/handlers/kannel/kannel_test.go @@ -32,25 +32,25 @@ var ignoreChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Receive KI Message", URL: receiveKIMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive KI Message", URL: receiveKIMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+68673076228", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp(""), ExpectedURN: "tel:+2349067554729", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'sender' required"}, - {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Status No Params", URL: statusNoParams, ExpectedStatus: 400, ExpectedResponse: "field 'status' required"}, - {Label: "Status Invalid Status", URL: statusInvalidStatus, ExpectedStatus: 400, ExpectedResponse: "unknown status '66', must be one of 1,2,4,8,16"}, - {Label: "Status Valid", URL: statusWired, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, + {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "field 'sender' required"}, + {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, + {Label: "Status No Params", URL: statusNoParams, ExpectedRespStatus: 400, ExpectedRespBody: "field 'status' required"}, + {Label: "Status Invalid Status", URL: statusInvalidStatus, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status '66', must be one of 1,2,4,8,16"}, + {Label: "Status Valid", URL: statusWired, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`}, } var ignoreTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Write Status Delivered", URL: statusDelivered, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`}, - {Label: "Ignore Status Wired", URL: statusWired, ExpectedStatus: 200, ExpectedResponse: `ignoring sent report`}, - {Label: "Ignore Status Sent", URL: statusSent, ExpectedStatus: 200, ExpectedResponse: `ignoring sent report`}, + {Label: "Write Status Delivered", URL: statusDelivered, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`}, + {Label: "Ignore Status Wired", URL: statusWired, ExpectedRespStatus: 200, ExpectedRespBody: `ignoring sent report`}, + {Label: "Ignore Status Sent", URL: statusSent, ExpectedRespStatus: 200, ExpectedRespBody: `ignoring sent report`}, } func TestHandler(t *testing.T) { @@ -75,45 +75,45 @@ func setSendURLWithQuery(s *httptest.Server, h courier.ChannelHandler, c courier var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", MsgText: "Simple Message", MsgURN: "tel:+250788383383", MsgHighPriority: false, - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"text": "Simple Message", "to": "+250788383383", "coding": "", "priority": "", "dlr-url": "https://localhost/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%d"}, SendPrep: setSendURL}, {Label: "Unicode Send", MsgText: "☺", MsgURN: "tel:+250788383383", MsgHighPriority: false, - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"text": "☺", "to": "+250788383383", "coding": "2", "charset": "utf8", "priority": ""}, SendPrep: setSendURL}, {Label: "Smart Encoding", MsgText: "Fancy “Smart” Quotes", MsgURN: "tel:+250788383383", MsgHighPriority: false, - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"text": `Fancy "Smart" Quotes`, "to": "+250788383383", "coding": "", "priority": ""}, SendPrep: setSendURL}, {Label: "Not Routable", MsgText: "Not Routable", MsgURN: "tel:+250788383383", MsgHighPriority: false, - ExpectedStatus: "F", - MockResponseBody: "Not routable. Do not try again.", MockResponseStatus: 403, + ExpectedMsgStatus: "F", + MockResponseBody: "Not routable. Do not try again.", MockResponseStatus: 403, ExpectedURLParams: map[string]string{"text": `Not Routable`, "to": "+250788383383", "coding": "", "priority": ""}, SendPrep: setSendURL}, {Label: "Error Sending", MsgText: "Error Message", MsgURN: "tel:+250788383383", MsgHighPriority: false, - ExpectedStatus: "E", - MockResponseBody: "1: Unknown channel", MockResponseStatus: 401, + ExpectedMsgStatus: "E", + MockResponseBody: "1: Unknown channel", MockResponseStatus: 401, ExpectedURLParams: map[string]string{"text": `Error Message`, "to": "+250788383383", "coding": "", "priority": ""}, SendPrep: setSendURL}, {Label: "Custom Params", MsgText: "Custom Params", MsgURN: "tel:+250788383383", MsgHighPriority: true, - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 201, + ExpectedMsgStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 201, ExpectedURLParams: map[string]string{"text": `Custom Params`, "to": "+250788383383", "coding": "", "priority": "1", "auth": "foo"}, SendPrep: setSendURLWithQuery}, {Label: "Send Attachment", MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgHighPriority: true, MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: `0: Accepted for delivery`, MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: `0: Accepted for delivery`, MockResponseStatus: 200, ExpectedURLParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "+250788383383", "from": "2020", "dlr-mask": "27"}, SendPrep: setSendURL}, } @@ -121,8 +121,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ var nationalSendTestCases = []ChannelSendTestCase{ {Label: "National Send", MsgText: "success", MsgURN: "tel:+250788383383", MsgHighPriority: true, - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"text": "success", "to": "788383383", "coding": "", "priority": "1", "dlr-mask": "3"}, SendPrep: setSendURL}, } diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index 0fb76a10b..fbfe0ab5d 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -258,37 +258,37 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Hello, world"), ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, - {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessageLast, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessageLast, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Last event"), ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, - {Label: "Receive Valid Image Message", URL: receiveURL, Data: receiveValidImageMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Image Message", URL: receiveURL, Data: receiveValidImageMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, - {Label: "Receive Valid Video Message", URL: receiveURL, Data: receiveValidVideoMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Video Message", URL: receiveURL, Data: receiveValidVideoMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, - {Label: "Receive Valid Video External Message", URL: receiveURL, Data: receiveValidVideoExternalMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Video External Message", URL: receiveURL, Data: receiveValidVideoExternalMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://example.com/original.mp4"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, - {Label: "Receive Valid Audio Message", URL: receiveURL, Data: receiveValidAudioMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Audio Message", URL: receiveURL, Data: receiveValidAudioMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, - {Label: "Receive Valid Location Message", URL: receiveURL, Data: receiveValidLocationMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Location Message", URL: receiveURL, Data: receiveValidLocationMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("my location"), ExpectedAttachments: []string{"geo:35.687574,139.729220"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, - {Label: "Missing message", URL: receiveURL, Data: missingMessage, ExpectedStatus: 200, ExpectedResponse: "ignoring request, no message", + {Label: "Missing message", URL: receiveURL, Data: missingMessage, ExpectedRespStatus: 200, ExpectedRespBody: "ignoring request, no message", PrepRequest: addValidSignature}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "invalid line id", + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "invalid line id", PrepRequest: addValidSignature}, - {Label: "No event request", URL: receiveURL, Data: noEvent, ExpectedStatus: 200, ExpectedResponse: "ignoring request, no message", + {Label: "No event request", URL: receiveURL, Data: noEvent, ExpectedRespStatus: 200, ExpectedRespBody: "ignoring request, no message", PrepRequest: addValidSignature}, - {Label: "Receive Valid Message Invalid signature", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 400, ExpectedResponse: "invalid request signature", + {Label: "Receive Valid Message Invalid signature", URL: receiveURL, Data: receiveValidMessage, ExpectedRespStatus: 400, ExpectedRespBody: "invalid request signature", PrepRequest: addInvalidSignature}, } @@ -335,7 +335,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Simple Message"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -346,7 +346,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Simple Message ☺"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -357,7 +357,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say,"},{"type":"text","text":"I need to keep adding more things to make it work"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -369,7 +369,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"audio","originalContentUrl":"http://mock.com/2345/test.m4a","duration":200},{"type":"text","text":"My Audio!"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -381,7 +381,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"video","originalContentUrl":"http://mock.com/5678/test.mp4","previewImageUrl":"http://mock.com/4567/test.jpg"},{"type":"text","text":"My Video!"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, @@ -394,7 +394,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"image","originalContentUrl":"http://mock.com/1234/test.jpg","previewImageUrl":"http://mock.com/1234/test.jpg"},{"type":"text","text":"My pic!"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -402,7 +402,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "My doc!", MsgURN: "line:uabcdefghij", MsgAttachments: []string{"application/pdf:http://mock.com/7890/test.pdf"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", MockResponseBody: `{}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, @@ -417,7 +417,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Sed hendrerit nisi vitae nisl ornare tristique.\nProin vulputate id justo non aliquet."}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -429,7 +429,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"replyToken":"nHuyWiB7yP5Zw52FIkcQobQuGDXCTA","messages":[{"type":"text","text":"Simple Message"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -441,7 +441,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Are you happy?","quickReply":{"items":[{"type":"action","action":{"type":"message","label":"Yes","text":"Yes"}},{"type":"action","action":{"type":"message","label":"No","text":"No"}}]}}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -454,7 +454,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer AccessToken"}, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"image","originalContentUrl":"http://mock.com/1234/test.jpg","previewImageUrl":"http://mock.com/1234/test.jpg"},{"type":"text","text":"Are you happy?","quickReply":{"items":[{"type":"action","action":{"type":"message","label":"Yes","text":"Yes"}},{"type":"action","action":{"type":"message","label":"No","text":"No"}}]}}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -474,8 +474,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ BodyContains: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Simple Message"}]}`, }: httpx.NewMockResponse(200, nil, []byte(`{}`)), }, - ExpectedStatus: "W", - SendPrep: setSendURL, + ExpectedMsgStatus: "W", + SendPrep: setSendURL, }, { Label: "Error Sending", @@ -484,7 +484,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"message": "Error"}`, MockResponseStatus: 403, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Error Sending"}]}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } diff --git a/handlers/m3tech/m3tech_test.go b/handlers/m3tech/m3tech_test.go index aeacb5a37..51ca02fe6 100644 --- a/handlers/m3tech/m3tech_test.go +++ b/handlers/m3tech/m3tech_test.go @@ -15,27 +15,27 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?from=+923161909799&text=hello+world", - Data: " ", - ExpectedStatus: 200, - ExpectedResponse: "SMS Accepted", - ExpectedMsgText: Sp("hello world"), - ExpectedURN: "tel:+923161909799", + Label: "Receive Valid Message", + URL: "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?from=+923161909799&text=hello+world", + Data: " ", + ExpectedRespStatus: 200, + ExpectedRespBody: "SMS Accepted", + ExpectedMsgText: Sp("hello world"), + ExpectedURN: "tel:+923161909799", }, { - Label: "Invalid URN", - URL: "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?from=MTN&text=hello+world", - Data: " ", - ExpectedStatus: 400, - ExpectedResponse: "phone number supplied is not a number", + Label: "Invalid URN", + URL: "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?from=MTN&text=hello+world", + Data: " ", + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", }, { - Label: "Receive No From", - URL: "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?text=hello", - Data: " ", - ExpectedStatus: 400, - ExpectedResponse: "missing required field 'from'", + Label: "Receive No From", + URL: "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?text=hello", + Data: " ", + ExpectedRespStatus: 400, + ExpectedRespBody: "missing required field 'from'", }, } @@ -55,8 +55,8 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, ExpectedURLParams: map[string]string{ "MobileNo": "250788383383", "SMS": "Simple Message", @@ -72,26 +72,26 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL}, {Label: "Unicode Send", MsgText: "☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, ExpectedURLParams: map[string]string{"SMS": "☺", "SMSType": "7"}, SendPrep: setSendURL}, {Label: "Smart Encoding", MsgText: "Fancy “Smart” Quotes", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, ExpectedURLParams: map[string]string{"SMS": `Fancy "Smart" Quotes`, "SMSType": "0"}, SendPrep: setSendURL}, {Label: "Send Attachment", MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: `[{"Response": "0"}]`, MockResponseStatus: 200, ExpectedURLParams: map[string]string{"SMS": "My pic!\nhttps://foo.bar/image.jpg", "SMSType": "0"}, SendPrep: setSendURL}, {Label: "Error Sending", MsgText: "Error Sending", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `[{"Response": "101"}]`, MockResponseStatus: 403, + ExpectedMsgStatus: "E", + MockResponseBody: `[{"Response": "101"}]`, MockResponseStatus: 403, SendPrep: setSendURL}, } diff --git a/handlers/macrokiosk/macrokiosk_test.go b/handlers/macrokiosk/macrokiosk_test.go index f3da52bca..3d59e3660 100644 --- a/handlers/macrokiosk/macrokiosk_test.go +++ b/handlers/macrokiosk/macrokiosk_test.go @@ -31,23 +31,23 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "-1", + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "-1", ExpectedMsgText: Sp("Hello"), ExpectedURN: "tel:+60124361111", ExpectedDate: time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC), ExpectedExternalID: "abc1234"}, - {Label: "Receive Valid via GET", URL: receiveURL + "?" + validReceive, ExpectedStatus: 200, ExpectedResponse: "-1", + {Label: "Receive Valid via GET", URL: receiveURL + "?" + validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "-1", ExpectedMsgText: Sp("Hello"), ExpectedURN: "tel:+60124361111", ExpectedDate: time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC), ExpectedExternalID: "abc1234"}, - {Label: "Receive Valid", URL: receiveURL, Data: validLongcodeReceive, ExpectedStatus: 200, ExpectedResponse: "-1", + {Label: "Receive Valid", URL: receiveURL, Data: validLongcodeReceive, ExpectedRespStatus: 200, ExpectedRespBody: "-1", ExpectedMsgText: Sp("Hello"), ExpectedURN: "tel:+60124361111", ExpectedDate: time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC), ExpectedExternalID: "abc1234"}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Missing Params", URL: receiveURL, Data: missingParamsReceive, ExpectedStatus: 400, ExpectedResponse: "missing shortcode, longcode, from or msisdn parameters"}, - {Label: "Invalid Params", URL: receiveURL, Data: invalidParamsReceive, ExpectedStatus: 400, ExpectedResponse: "missing shortcode, longcode, from or msisdn parameters"}, - {Label: "Invalid Address Params", URL: receiveURL, Data: invalidAddress, ExpectedStatus: 400, ExpectedResponse: "invalid to number [1515], expecting [2020]"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, + {Label: "Missing Params", URL: receiveURL, Data: missingParamsReceive, ExpectedRespStatus: 400, ExpectedRespBody: "missing shortcode, longcode, from or msisdn parameters"}, + {Label: "Invalid Params", URL: receiveURL, Data: invalidParamsReceive, ExpectedRespStatus: 400, ExpectedRespBody: "missing shortcode, longcode, from or msisdn parameters"}, + {Label: "Invalid Address Params", URL: receiveURL, Data: invalidAddress, ExpectedRespStatus: 400, ExpectedRespBody: "invalid to number [1515], expecting [2020]"}, - {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, - {Label: "Wired Status", URL: statusURL, Data: processingStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"W"`}, - {Label: "Unknown Status", URL: statusURL, Data: unknownStatus, ExpectedStatus: 200, ExpectedResponse: `ignoring unknown status 'UNKNOWN'`}, + {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`}, + {Label: "Wired Status", URL: statusURL, Data: processingStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"W"`}, + {Label: "Unknown Status", URL: statusURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedRespBody: `ignoring unknown status 'UNKNOWN'`}, } func TestHandler(t *testing.T) { @@ -67,7 +67,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "abc123", MockResponseBody: `{ "MsgID":"abc123" }`, MockResponseStatus: 200, @@ -80,7 +80,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Long Send", MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "abc123", MockResponseBody: `{ "MsgID":"abc123" }`, MockResponseStatus: 200, @@ -94,7 +94,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "abc123", MockResponseBody: `{ "MsgID":"abc123" }`, MockResponseStatus: 200, @@ -107,7 +107,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "No External Id", MsgText: "No External ID", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", + ExpectedMsgStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to parse response body from Macrokiosk", "")}, @@ -120,7 +120,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Error Sending", MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", + ExpectedMsgStatus: "E", MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, ExpectedRequestBody: `{"user":"Username","pass":"Password","to":"250788383383","text":"Error Message","from":"macro","servid":"service-id","type":"0"}`, diff --git a/handlers/mblox/mblox_test.go b/handlers/mblox/mblox_test.go index 768a35e3d..907d41ac8 100644 --- a/handlers/mblox/mblox_test.go +++ b/handlers/mblox/mblox_test.go @@ -62,16 +62,16 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", ExpectedMsgText: Sp("Hello World"), ExpectedURN: "tel:+12067799294", ExpectedDate: time.Date(2016, 3, 30, 19, 33, 06, 643000000, time.UTC), ExpectedExternalID: "OzQ5UqIOdoY8"}, - {Label: "Receive Missing Params", URL: receiveURL, Data: missingParamsRecieve, ExpectedStatus: 400, ExpectedResponse: "missing one of 'id', 'from', 'to', 'body' or 'received_at' in request body"}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, + {Label: "Receive Missing Params", URL: receiveURL, Data: missingParamsRecieve, ExpectedRespStatus: 400, ExpectedRespBody: "missing one of 'id', 'from', 'to', 'body' or 'received_at' in request body"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, - {Label: "Status Valid", URL: receiveURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`}, - {Label: "Status Unknown", URL: receiveURL, Data: unknownStatus, ExpectedStatus: 400, ExpectedResponse: `unknown status 'INVALID'`}, - {Label: "Status Missing Batch ID", URL: receiveURL, Data: missingBatchID, ExpectedStatus: 400, ExpectedResponse: "missing one of 'batch_id' or 'status' in request body"}, + {Label: "Status Valid", URL: receiveURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`}, + {Label: "Status Unknown", URL: receiveURL, Data: unknownStatus, ExpectedRespStatus: 400, ExpectedRespBody: `unknown status 'INVALID'`}, + {Label: "Status Missing Batch ID", URL: receiveURL, Data: missingBatchID, ExpectedRespStatus: 400, ExpectedRespBody: "missing one of 'batch_id' or 'status' in request body"}, } func TestHandler(t *testing.T) { @@ -91,7 +91,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", MockResponseBody: `{ "id":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, @@ -105,7 +105,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Long Send", MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", MockResponseBody: `{ "id":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, @@ -120,7 +120,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", MockResponseBody: `{ "id":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, @@ -134,7 +134,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "No External Id", MsgText: "No External ID", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", + ExpectedMsgStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to parse response body from MBlox", "")}, @@ -148,7 +148,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Error Sending", MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", + ExpectedMsgStatus: "E", MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, ExpectedRequestBody: `{"from":"2020","to":["250788383383"],"body":"Error Message","delivery_report":"per_recipient"}`, diff --git a/handlers/messangi/messangi_test.go b/handlers/messangi/messangi_test.go index 49e62c321..98c87a33f 100644 --- a/handlers/messangi/messangi_test.go +++ b/handlers/messangi/messangi_test.go @@ -19,19 +19,19 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: "mo=Msg&mobile=18765422035", - ExpectedStatus: 200, - ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+18765422035"}, + Label: "Receive Valid", + URL: receiveURL, + Data: "mo=Msg&mobile=18765422035", + ExpectedRespStatus: 200, + ExpectedRespBody: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+18765422035"}, { - Label: "Receive Missing Number", - URL: receiveURL, - Data: "mo=Msg", - ExpectedStatus: 400, - ExpectedResponse: "required field 'mobile'"}, + Label: "Receive Missing Number", + URL: receiveURL, + Data: "mo=Msg", + ExpectedRespStatus: 400, + ExpectedRespBody: "required field 'mobile'"}, } func TestHandler(t *testing.T) { @@ -53,7 +53,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+18765422035", MockResponseBody: `sendMTOKCompleted`, MockResponseStatus: 200, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -62,7 +62,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+18765422035", MockResponseBody: `sendMTOKCompleted`, MockResponseStatus: 200, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -72,7 +72,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MockResponseBody: `sendMTOKCompleted`, MockResponseStatus: 200, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -81,7 +81,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+18765422035", MockResponseBody: "", MockResponseStatus: 404, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -90,7 +90,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+18765422035", MockResponseBody: `sendMTERRORCompleted`, MockResponseStatus: 200, - ExpectedStatus: "F", + ExpectedMsgStatus: "F", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid response description: Completed", "")}, SendPrep: setSendURL, }, diff --git a/handlers/mtarget/mtarget_test.go b/handlers/mtarget/mtarget_test.go index 44beb94cf..2a91e9504 100644 --- a/handlers/mtarget/mtarget_test.go +++ b/handlers/mtarget/mtarget_test.go @@ -32,22 +32,22 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("hello world"), ExpectedURN: "tel:+923161909799"}, - {Label: "Invalid URN", URL: receiveURL, Data: receiveInvalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Receive Stop", URL: receiveURL, Data: receiveStop, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedURN: "tel:+923161909799", ExpectedChannelEvent: courier.StopContact}, - {Label: "Receive Missing From", URL: receiveURL, Data: receiveMissingFrom, ExpectedStatus: 400, ExpectedResponse: "missing required field 'Msisdn'"}, + {Label: "Invalid URN", URL: receiveURL, Data: receiveInvalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, + {Label: "Receive Stop", URL: receiveURL, Data: receiveStop, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + ExpectedURN: "tel:+923161909799", ExpectedEvent: courier.StopContact}, + {Label: "Receive Missing From", URL: receiveURL, Data: receiveMissingFrom, ExpectedRespStatus: 400, ExpectedRespBody: "missing required field 'Msisdn'"}, - {Label: "Receive Part 2", URL: receiveURL, Data: receivePart2, ExpectedStatus: 200, ExpectedResponse: "received"}, - {Label: "Receive Part 1", URL: receiveURL, Data: receivePart1, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Part 2", URL: receiveURL, Data: receivePart2, ExpectedRespStatus: 200, ExpectedRespBody: "received"}, + {Label: "Receive Part 1", URL: receiveURL, Data: receivePart1, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("hello world"), ExpectedURN: "tel:+923161909799"}, - {Label: "Status Delivered", URL: statusURL, Data: statusDelivered, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Status Delivered", URL: statusURL, Data: statusDelivered, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedExternalID: "12a7ee90-50ce-11e7-80ae-00000a0a643c", ExpectedMsgStatus: "D"}, - {Label: "Status Failed", URL: statusURL, Data: statusFailed, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Status Failed", URL: statusURL, Data: statusFailed, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedExternalID: "12a7ee90-50ce-11e7-80ae-00000a0a643c", ExpectedMsgStatus: "F"}, - {Label: "Status Missing ID", URL: statusURL, Data: statusMissingID, ExpectedStatus: 400, ExpectedResponse: "missing required field 'MsgId'"}, + {Label: "Status Missing ID", URL: statusURL, Data: statusMissingID, ExpectedRespStatus: 400, ExpectedRespBody: "missing required field 'MsgId'"}, } func TestHandler(t *testing.T) { @@ -78,8 +78,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ "serviceid": "2020", "allowunicode": "true", }, - ExpectedStatus: "W", - SendPrep: setSendURL, + ExpectedMsgStatus: "W", + SendPrep: setSendURL, }, { Label: "Unicode Send", @@ -88,7 +88,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"results":[{"code": "0", "ticket": "externalID"}]}`, MockResponseStatus: 200, ExpectedURLParams: map[string]string{"msg": "☺"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -99,7 +99,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"results":[{"code": "0", "ticket": "externalID"}]}`, MockResponseStatus: 200, ExpectedURLParams: map[string]string{"msg": "My pic!\nhttps://foo.bar/image.jpg"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -108,7 +108,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `{"results":[{"code": "3", "ticket": "null"}]}`, MockResponseStatus: 403, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -117,7 +117,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `{"results":[{"code": "3", "ticket": "null"}]}`, MockResponseStatus: 200, - ExpectedStatus: "F", + ExpectedMsgStatus: "F", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Error status code, failing permanently", "")}, SendPrep: setSendURL, }, diff --git a/handlers/nexmo/nexmo_test.go b/handlers/nexmo/nexmo_test.go index 779dfe750..4596699b6 100644 --- a/handlers/nexmo/nexmo_test.go +++ b/handlers/nexmo/nexmo_test.go @@ -30,20 +30,20 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Valid Receive", URL: receiveValidMessage, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Valid Receive", URL: receiveValidMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, - {Label: "Invalid URN", URL: receiveInvalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Valid Receive Post", URL: receiveURL, ExpectedStatus: 200, ExpectedResponse: "Accepted", Data: receiveValidMessageBody, + {Label: "Invalid URN", URL: receiveInvalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, + {Label: "Valid Receive Post", URL: receiveURL, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", Data: receiveValidMessageBody, ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, - {Label: "Receive URL check", URL: receiveURL, ExpectedStatus: 200, ExpectedResponse: "no to parameter, ignored"}, - {Label: "Status URL check", URL: statusURL, ExpectedStatus: 200, ExpectedResponse: "no messageId parameter, ignored"}, + {Label: "Receive URL check", URL: receiveURL, ExpectedRespStatus: 200, ExpectedRespBody: "no to parameter, ignored"}, + {Label: "Status URL check", URL: statusURL, ExpectedRespStatus: 200, ExpectedRespBody: "no messageId parameter, ignored"}, - {Label: "Status delivered", URL: statusDelivered, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "external1"}, - {Label: "Status expired", URL: statusExpired, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, ExpectedExternalID: "external1"}, - {Label: "Status failed", URL: statusFailed, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, ExpectedExternalID: "external1"}, - {Label: "Status accepted", URL: statusAccepted, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`, ExpectedExternalID: "external1"}, - {Label: "Status buffered", URL: statusBuffered, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`, ExpectedExternalID: "external1"}, - {Label: "Status unexpected", URL: statusUnexpected, ExpectedStatus: 200, ExpectedResponse: "ignoring unknown status report", ExpectedExternalID: "external1"}, + {Label: "Status delivered", URL: statusDelivered, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "external1"}, + {Label: "Status expired", URL: statusExpired, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, ExpectedExternalID: "external1"}, + {Label: "Status failed", URL: statusFailed, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, ExpectedExternalID: "external1"}, + {Label: "Status accepted", URL: statusAccepted, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, ExpectedExternalID: "external1"}, + {Label: "Status buffered", URL: statusBuffered, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, ExpectedExternalID: "external1"}, + {Label: "Status unexpected", URL: statusUnexpected, ExpectedRespStatus: 200, ExpectedRespBody: "ignoring unknown status report", ExpectedExternalID: "external1"}, } func TestHandler(t *testing.T) { @@ -67,7 +67,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -78,7 +78,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Unicode ☺", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "unicode"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -89,7 +89,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "I need to keep adding more things to make it work", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -101,7 +101,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"messages":[{"status":"0","message-id":"1002"}]}`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -112,7 +112,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"messages":[{"status":"10"}]}`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Error status", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("failed to send message, received error status [10]", "")}, SendPrep: setSendURL, }, @@ -123,7 +123,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `Error`, MockResponseStatus: 400, ExpectedPostParams: map[string]string{"text": "Error Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -133,7 +133,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: "Invalid API token", MockResponseStatus: 401, ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -143,7 +143,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"messages":[{"status":"1","error-text":"Throughput Rate Exceeded - please wait [ 250 ] and retry"}]}`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("failed to send message, received error status [1]", "")}, SendPrep: setSendURL, }, diff --git a/handlers/novo/novo_test.go b/handlers/novo/novo_test.go index 23d0916d3..078960fe5 100644 --- a/handlers/novo/novo_test.go +++ b/handlers/novo/novo_test.go @@ -23,29 +23,29 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Headers: map[string]string{"Authorization": "sesame"}, - Data: "text=Msg&from=18686846481", - ExpectedStatus: 200, - ExpectedResponse: "Message Accepted", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+18686846481", + Label: "Receive Valid", + URL: receiveURL, + Headers: map[string]string{"Authorization": "sesame"}, + Data: "text=Msg&from=18686846481", + ExpectedRespStatus: 200, + ExpectedRespBody: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+18686846481", }, { - Label: "Receive Missing Number", - URL: receiveURL, - Headers: map[string]string{"Authorization": "sesame"}, - Data: "text=Msg", - ExpectedStatus: 400, - ExpectedResponse: "required field 'from'", + Label: "Receive Missing Number", + URL: receiveURL, + Headers: map[string]string{"Authorization": "sesame"}, + Data: "text=Msg", + ExpectedRespStatus: 400, + ExpectedRespBody: "required field 'from'", }, { - Label: "Receive Missing Authorization", - URL: receiveURL, - Data: "text=Msg&from=18686846481", - ExpectedStatus: 401, - ExpectedResponse: "invalid Authorization header", + Label: "Receive Missing Authorization", + URL: receiveURL, + Data: "text=Msg&from=18686846481", + ExpectedRespStatus: 401, + ExpectedRespBody: "invalid Authorization header", }, } @@ -68,7 +68,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+18686846481", MockResponseBody: `{"blastId": "-437733473338","status": "FINISHED","type": "SMS","statusDescription": "Finished"}`, MockResponseStatus: 200, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", SendPrep: setSendURL, }, @@ -78,7 +78,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+18686846481", MockResponseBody: `{"blastId": "-437733473338","status": "FINISHED","type": "SMS","statusDescription": "Finished"}`, MockResponseStatus: 200, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", SendPrep: setSendURL, }, @@ -89,7 +89,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MockResponseBody: `{"blastId": "-437733473338","status": "FINISHED","type": "SMS","statusDescription": "Finished"}`, MockResponseStatus: 200, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", SendPrep: setSendURL, }, @@ -99,7 +99,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+18686846481", MockResponseBody: `{"error": "Incorrect Query String Authentication ","expectedQueryString": "8868;18686846480;test;"}`, MockResponseStatus: 200, - ExpectedStatus: "F", + ExpectedMsgStatus: "F", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received invalid response", "")}, SendPrep: setSendURL, }, @@ -109,7 +109,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+18686846481", MockResponseBody: `{"error": "Incorrect Query String Authentication ","expectedQueryString": "8868;18686846480;test;"}`, MockResponseStatus: 200, - ExpectedStatus: "F", + ExpectedMsgStatus: "F", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received invalid response", "")}, SendPrep: setSendURL, }, diff --git a/handlers/playmobile/playmobile_test.go b/handlers/playmobile/playmobile_test.go index 6f8f4ed3a..48de394c1 100644 --- a/handlers/playmobile/playmobile_test.go +++ b/handlers/playmobile/playmobile_test.go @@ -74,50 +74,50 @@ var ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: validReceive, - ExpectedResponse: "Accepted", - ExpectedStatus: 200, - ExpectedMsgText: Sp("SMS Response Accepted"), - ExpectedURN: "tel:+998999999999", + Label: "Receive Valid", + URL: receiveURL, + Data: validReceive, + ExpectedRespBody: "Accepted", + ExpectedRespStatus: 200, + ExpectedMsgText: Sp("SMS Response Accepted"), + ExpectedURN: "tel:+998999999999", }, { - Label: "Receive Missing MSISDN", - URL: receiveURL, - Data: invalidReceive, - ExpectedResponse: "missing required fields msidsn or id", - ExpectedStatus: 400, + Label: "Receive Missing MSISDN", + URL: receiveURL, + Data: invalidReceive, + ExpectedRespBody: "missing required fields msidsn or id", + ExpectedRespStatus: 400, }, { - Label: "No Messages", - URL: receiveURL, - Data: noMessages, - ExpectedResponse: "no messages, ignored", - ExpectedStatus: 200, + Label: "No Messages", + URL: receiveURL, + Data: noMessages, + ExpectedRespBody: "no messages, ignored", + ExpectedRespStatus: 200, }, { - Label: "Invalid XML", - URL: receiveURL, - Data: invalidXML, - ExpectedResponse: "", - ExpectedStatus: 405, + Label: "Invalid XML", + URL: receiveURL, + Data: invalidXML, + ExpectedRespBody: "", + ExpectedRespStatus: 405, }, { - Label: "Receive With Prefix", - URL: receiveURL, - Data: receiveWithPrefix, - ExpectedResponse: "Accepted", - ExpectedStatus: 200, - ExpectedMsgText: Sp("SMS Response Accepted"), - ExpectedURN: "tel:+998999999999", + Label: "Receive With Prefix", + URL: receiveURL, + Data: receiveWithPrefix, + ExpectedRespBody: "Accepted", + ExpectedRespStatus: 200, + ExpectedMsgText: Sp("SMS Response Accepted"), + ExpectedURN: "tel:+998999999999", }, { - Label: "Receive With Prefix Only", - URL: receiveURL, - Data: receiveWithPrefixOnly, - ExpectedResponse: "no text", - ExpectedStatus: 400, + Label: "Receive With Prefix Only", + URL: receiveURL, + Data: receiveWithPrefixOnly, + ExpectedRespBody: "no text", + ExpectedRespStatus: 400, }, } @@ -137,7 +137,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", MsgText: "Simple Message", MsgURN: "tel:99999999999", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", MockResponseBody: "Request is received", MockResponseStatus: 200, @@ -146,7 +146,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Long Send", MsgText: "This is a longer message than 640 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, This is a longer message than 640 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, This is a longer message than 640 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, This is a longer message than 640 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, now, I need to keep adding more things to make it work", MsgURN: "tel:99999999999", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", MockResponseBody: "Request is received", MockResponseStatus: 200, @@ -156,7 +156,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "My pic!", MsgURN: "tel:+18686846481", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", MockResponseBody: validMessage, MockResponseStatus: 200, @@ -164,14 +164,14 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Invalid JSON Response", MsgText: "Error Sending", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", + ExpectedMsgStatus: "E", MockResponseStatus: 400, MockResponseBody: "not json", SendPrep: setSendURL}, {Label: "Missing Message ID", MsgText: missingMessageID, MsgURN: "tel:+250788383383", - ExpectedStatus: "E", + ExpectedMsgStatus: "E", MockResponseStatus: 400, MockResponseBody: "{}", SendPrep: setSendURL}, diff --git a/handlers/plivo/plivo_test.go b/handlers/plivo/plivo_test.go index 6ec036b1b..67e081080 100644 --- a/handlers/plivo/plivo_test.go +++ b/handlers/plivo/plivo_test.go @@ -29,16 +29,16 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", ExpectedMsgText: Sp("Hello"), ExpectedURN: "tel:+60124361111", ExpectedExternalID: "abc1234"}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Invalid Address Params", URL: receiveURL, Data: invalidAddress, ExpectedStatus: 400, ExpectedResponse: "invalid to number [1515], expecting [2020]"}, - {Label: "Missing Params", URL: receiveURL, Data: missingParams, ExpectedStatus: 400, ExpectedResponse: "Field validation for 'To' failed"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, + {Label: "Invalid Address Params", URL: receiveURL, Data: invalidAddress, ExpectedRespStatus: 400, ExpectedRespBody: "invalid to number [1515], expecting [2020]"}, + {Label: "Missing Params", URL: receiveURL, Data: missingParams, ExpectedRespStatus: 400, ExpectedRespBody: "Field validation for 'To' failed"}, - {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`}, - {Label: "Sent Status", URL: statusURL, Data: validSentStatus, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`}, - {Label: "Invalid Status Address", URL: statusURL, Data: invalidStatusAddress, ExpectedStatus: 400, ExpectedResponse: "invalid to number [1515], expecting [2020]"}, - {Label: "Unkown Status", URL: statusURL, Data: unknownStatus, ExpectedStatus: 200, ExpectedResponse: `ignoring unknown status 'UNKNOWN'`}, + {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`}, + {Label: "Sent Status", URL: statusURL, Data: validSentStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`}, + {Label: "Invalid Status Address", URL: statusURL, Data: invalidStatusAddress, ExpectedRespStatus: 400, ExpectedRespBody: "invalid to number [1515], expecting [2020]"}, + {Label: "Unkown Status", URL: statusURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedRespBody: `ignoring unknown status 'UNKNOWN'`}, } func TestHandler(t *testing.T) { @@ -58,7 +58,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "abc123", MockResponseBody: `{ "message_uuid":["abc123"] }`, MockResponseStatus: 200, @@ -72,7 +72,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Long Send", MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "abc123", MockResponseBody: `{ "message_uuid":["abc123"] }`, MockResponseStatus: 200, @@ -87,7 +87,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "abc123", MockResponseBody: `{ "message_uuid":["abc123"] }`, MockResponseStatus: 200, @@ -101,7 +101,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "No External Id", MsgText: "No External ID", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", + ExpectedMsgStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to parse response body from Plivo", "")}, @@ -115,7 +115,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Error Sending", MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", + ExpectedMsgStatus: "E", MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, ExpectedRequestBody: `{"src":"2020","dst":"250788383383","text":"Error Message","url":"https://localhost/c/pl/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status","method":"POST"}`, diff --git a/handlers/redrabbit/redrabbit_test.go b/handlers/redrabbit/redrabbit_test.go index 971996244..74c9b6420 100644 --- a/handlers/redrabbit/redrabbit_test.go +++ b/handlers/redrabbit/redrabbit_test.go @@ -17,8 +17,8 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "SENT", MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: "SENT", MockResponseStatus: 200, ExpectedURLParams: map[string]string{ "LoginName": "Username", "Password": "Password", @@ -31,8 +31,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL}, {Label: "Unicode Send", MsgText: "☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "SENT", MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: "SENT", MockResponseStatus: 200, ExpectedURLParams: map[string]string{ "LoginName": "Username", "Password": "Password", @@ -45,10 +45,10 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Longer Unicode Send", - MsgText: "This is a message more than seventy characters with some unicode ☺ in them", - MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "SENT", MockResponseStatus: 200, + MsgText: "This is a message more than seventy characters with some unicode ☺ in them", + MsgURN: "tel:+250788383383", + ExpectedMsgStatus: "W", + MockResponseBody: "SENT", MockResponseStatus: 200, ExpectedURLParams: map[string]string{ "LoginName": "Username", "Password": "Password", @@ -61,10 +61,10 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, SendPrep: setSendURL}, {Label: "Long Send", - MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "SENT", MockResponseStatus: 200, + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + ExpectedMsgStatus: "W", + MockResponseBody: "SENT", MockResponseStatus: 200, ExpectedURLParams: map[string]string{ "LoginName": "Username", "Password": "Password", @@ -78,8 +78,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL}, {Label: "Send Attachment", MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: "SENT", MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: "SENT", MockResponseStatus: 200, ExpectedURLParams: map[string]string{ "LoginName": "Username", "Password": "Password", @@ -92,8 +92,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL}, {Label: "Error Sending", MsgText: "Error Sending", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: "Error", MockResponseStatus: 403, + ExpectedMsgStatus: "E", + MockResponseBody: "Error", MockResponseStatus: 403, SendPrep: setSendURL}, } diff --git a/handlers/rocketchat/rocketchat_test.go b/handlers/rocketchat/rocketchat_test.go index 66f4c345e..e71ed1fe1 100644 --- a/handlers/rocketchat/rocketchat_test.go +++ b/handlers/rocketchat/rocketchat_test.go @@ -56,11 +56,11 @@ var testCases = []handlers.ChannelHandleTestCase{ Headers: map[string]string{ "Authorization": "Token 123456789", }, - Data: helloMsg, - ExpectedURN: "rocketchat:direct:john.doe#john.doe", - ExpectedMsgText: handlers.Sp("Hello World"), - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + Data: helloMsg, + ExpectedURN: "rocketchat:direct:john.doe#john.doe", + ExpectedMsgText: handlers.Sp("Hello World"), + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", }, { Label: "Receive Attachment Msg", @@ -71,8 +71,8 @@ var testCases = []handlers.ChannelHandleTestCase{ Data: attachmentMsg, ExpectedURN: "rocketchat:livechat:onrMgdKbpX9Qqtvoi", ExpectedAttachments: []string{"https://link.to/image.jpg"}, - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", }, { Label: "Don't Receive Empty Msg", @@ -80,9 +80,9 @@ var testCases = []handlers.ChannelHandleTestCase{ Headers: map[string]string{ "Authorization": "Token 123456789", }, - Data: emptyMsg, - ExpectedStatus: 400, - ExpectedResponse: "no text or attachment", + Data: emptyMsg, + ExpectedRespStatus: 400, + ExpectedRespBody: "no text or attachment", }, { Label: "Invalid Authorization", @@ -90,9 +90,9 @@ var testCases = []handlers.ChannelHandleTestCase{ Headers: map[string]string{ "Authorization": "123456789", }, - Data: emptyMsg, - ExpectedStatus: 401, - ExpectedResponse: "invalid Authorization header", + Data: emptyMsg, + ExpectedRespStatus: 401, + ExpectedRespBody: "invalid Authorization header", }, } @@ -113,7 +113,7 @@ var sendTestCases = []handlers.ChannelSendTestCase{ Label: "Plain Send", MsgText: "Simple Message", MsgURN: "rocketchat:direct:john.doe#john.doe", - ExpectedStatus: "S", + ExpectedMsgStatus: "S", ExpectedRequestBody: `{"user":"direct:john.doe","bot":"rocket.cat","text":"Simple Message"}`, MockResponseStatus: 201, MockResponseBody: `{"id":"iNKE8a6k6cjbqWhWd"}`, @@ -124,7 +124,7 @@ var sendTestCases = []handlers.ChannelSendTestCase{ Label: "Send Attachment", MsgURN: "rocketchat:livechat:onrMgdKbpX9Qqtvoi", MsgAttachments: []string{"application/pdf:https://link.to/attachment.pdf"}, - ExpectedStatus: "S", + ExpectedMsgStatus: "S", ExpectedRequestBody: `{"user":"livechat:onrMgdKbpX9Qqtvoi","bot":"rocket.cat","attachments":[{"type":"application/pdf","url":"https://link.to/attachment.pdf"}]}`, MockResponseStatus: 201, MockResponseBody: `{"id":"iNKE8a6k6cjbqWhWd"}`, @@ -136,7 +136,7 @@ var sendTestCases = []handlers.ChannelSendTestCase{ MsgURN: "rocketchat:direct:john.doe", MsgText: "Simple Message", MsgAttachments: []string{"application/pdf:https://link.to/attachment.pdf"}, - ExpectedStatus: "S", + ExpectedMsgStatus: "S", ExpectedRequestBody: `{"user":"direct:john.doe","bot":"rocket.cat","text":"Simple Message","attachments":[{"type":"application/pdf","url":"https://link.to/attachment.pdf"}]}`, MockResponseStatus: 201, MockResponseBody: `{"id":"iNKE8a6k6cjbqWhWd"}`, diff --git a/handlers/shaqodoon/shaqodoon_test.go b/handlers/shaqodoon/shaqodoon_test.go index 90c69df15..1eb63d32e 100644 --- a/handlers/shaqodoon/shaqodoon_test.go +++ b/handlers/shaqodoon/shaqodoon_test.go @@ -27,20 +27,20 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, - {Label: "Receive Badly Escaped", URL: receiveBadlyEscaped, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Badly Escaped", URL: receiveBadlyEscaped, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+252999999999"}, - {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp(""), ExpectedURN: "tel:+2349067554729"}, - {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC)}, - {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "empty", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC)}, - {Label: "Receive invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'from' required"}, - {Label: "Receive No Sender", URL: receiveNoSender, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'from' required"}, - {Label: "Receive Invalid Date", URL: receiveInvalidDate, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "invalid date format, must be RFC 3339"}, + {Label: "Receive invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, + {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "field 'from' required"}, + {Label: "Receive No Sender", URL: receiveNoSender, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "field 'from' required"}, + {Label: "Receive Invalid Date", URL: receiveInvalidDate, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "invalid date format, must be RFC 3339"}, } func TestHandler(t *testing.T) { @@ -58,26 +58,26 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var getSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"msg": "Simple Message", "to": "250788383383", "from": "2020"}, SendPrep: setSendURL}, {Label: "Unicode Send", MsgText: "☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"msg": "☺", "to": "250788383383", "from": "2020"}, SendPrep: setSendURL}, {Label: "Error Sending", MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: "1: Unknown channel", MockResponseStatus: 401, + ExpectedMsgStatus: "E", + MockResponseBody: "1: Unknown channel", MockResponseStatus: 401, ExpectedURLParams: map[string]string{"msg": `Error Message`, "to": "250788383383"}, SendPrep: setSendURL}, {Label: "Send Attachment", MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: `0: Accepted for delivery`, MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: `0: Accepted for delivery`, MockResponseStatus: 200, ExpectedURLParams: map[string]string{"msg": "My pic!\nhttps://foo.bar/image.jpg", "to": "250788383383", "from": "2020"}, SendPrep: setSendURL}, } diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 5e8d8c8e8..7c237c1ff 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -136,8 +136,8 @@ var handleTestCases = []ChannelHandleTestCase{ Data: helloMsg, ExpectedURN: "slack:U0123ABCDEF", ExpectedMsgText: Sp("Hello World!"), - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", ExpectedExternalID: "Ev0PV52K21", }, { @@ -148,8 +148,8 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedAttachments: []string{"https://files.slack.com/files-pri/T03CN5KTA6S-F03GTH43SSF/download/batata.jpg?pub_secret=39fcf577f2"}, ExpectedURN: "slack:U0123ABCDEF", ExpectedMsgText: Sp(""), - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", ExpectedExternalID: "Ev0PV52K21", }, { @@ -160,8 +160,8 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedAttachments: []string{"https://files.slack.com/files-pri/T03CN5KTA6S-F03GWURCZL4/download/here_we_go_again.mp3?pub_secret=471020b300"}, ExpectedURN: "slack:U0123ABCDEF", ExpectedMsgText: Sp(""), - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", ExpectedExternalID: "Ev0PV52K21", }, { @@ -171,8 +171,8 @@ var handleTestCases = []ChannelHandleTestCase{ Data: videoFileMsg, ExpectedURN: "slack:U0123ABCDEF", ExpectedMsgText: Sp(""), - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", ExpectedExternalID: "Ev0PV52K21", }, } @@ -185,7 +185,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"ok":true,"channel":"U0123ABCDEF"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"channel":"U0123ABCDEF","text":"Simple Message"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendUrl, }, { @@ -195,7 +195,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"ok":true,"channel":"U0123ABCDEF"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"channel":"U0123ABCDEF","text":"☺"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendUrl, }, { @@ -205,7 +205,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"ok":false,"error":"invalid_auth"}`, MockResponseStatus: 200, ExpectedRequestBody: `{"channel":"U0123ABCDEF","text":"Hello"}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("invalid_auth", "")}, SendPrep: setSendUrl, }, @@ -224,8 +224,8 @@ var fileSendTestCases = []ChannelSendTestCase{ BodyContains: "image.png", }: httpx.NewMockResponse(200, nil, []byte(`{"ok":true,"file":{"id":"F1L3SL4CK1D"}}`)), }, - ExpectedStatus: "W", - SendPrep: setSendUrl, + ExpectedMsgStatus: "W", + SendPrep: setSendUrl, }, { Label: "Send Image", @@ -239,8 +239,8 @@ var fileSendTestCases = []ChannelSendTestCase{ BodyContains: "image.png", }: httpx.NewMockResponse(200, nil, []byte(`{"ok":true,"file":{"id":"F1L3SL4CK1D"}}`)), }, - ExpectedStatus: "W", - SendPrep: setSendUrl, + ExpectedMsgStatus: "W", + SendPrep: setSendUrl, }, } @@ -265,12 +265,12 @@ func TestSendFiles(t *testing.T) { func TestVerification(t *testing.T) { RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ - {Label: "Valid token", URL: receiveURL, ExpectedStatus: 200, + {Label: "Valid token", URL: receiveURL, ExpectedRespStatus: 200, Data: `{"token":"one-long-verification-token","challenge":"challenge123","type":"url_verification"}`, Headers: map[string]string{"content-type": "text/plain"}, - ExpectedResponse: "challenge123", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + ExpectedRespBody: "challenge123", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, }, - {Label: "Invalid token", URL: receiveURL, ExpectedStatus: 403, + {Label: "Invalid token", URL: receiveURL, ExpectedRespStatus: 403, Data: `{"token":"abc321","challenge":"challenge123","type":"url_verification"}`, Headers: map[string]string{"content-type": "text/plain"}, }, diff --git a/handlers/smscentral/smscentral_test.go b/handlers/smscentral/smscentral_test.go index 32b51377d..4b5e376aa 100644 --- a/handlers/smscentral/smscentral_test.go +++ b/handlers/smscentral/smscentral_test.go @@ -19,43 +19,43 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: receiveURL, - Data: "mobile=%2B2349067554729&message=Join", - ExpectedStatus: 200, - ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", + Label: "Receive Valid Message", + URL: receiveURL, + Data: "mobile=%2B2349067554729&message=Join", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", }, { - Label: "Receive No Message", - URL: receiveURL, - Data: "mobile=%2B2349067554729", - ExpectedStatus: 200, - ExpectedResponse: "Accepted", - ExpectedMsgText: Sp(""), - ExpectedURN: "tel:+2349067554729", + Label: "Receive No Message", + URL: receiveURL, + Data: "mobile=%2B2349067554729", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedURN: "tel:+2349067554729", }, { - Label: "Receive invalid URN", - URL: receiveURL, - Data: "mobile=MTN&message=Join", - ExpectedStatus: 400, - ExpectedResponse: "phone number supplied is not a number", + Label: "Receive invalid URN", + URL: receiveURL, + Data: "mobile=MTN&message=Join", + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", }, { - Label: "Receive No Params", - URL: receiveURL, - Data: "none", - ExpectedStatus: 400, - ExpectedResponse: "field 'mobile' required", + Label: "Receive No Params", + URL: receiveURL, + Data: "none", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'mobile' required", }, { - Label: "Receive No Sender", - URL: receiveURL, - Data: "message=Join", - ExpectedStatus: 400, - ExpectedResponse: "field 'mobile' required", + Label: "Receive No Sender", + URL: receiveURL, + Data: "message=Join", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'mobile' required", }, } @@ -75,26 +75,26 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: `[{"id": "1002"}]`, MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: `[{"id": "1002"}]`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"content": "Simple Message", "mobile": "250788383383", "pass": "Password", "user": "Username"}, SendPrep: setSendURL}, {Label: "Unicode Send", MsgText: "☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: `[{"id": "1002"}]`, MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: `[{"id": "1002"}]`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"content": "☺", "mobile": "250788383383", "pass": "Password", "user": "Username"}, SendPrep: setSendURL}, {Label: "Send Attachment", MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: `[{ "id": "1002" }]`, MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: `[{ "id": "1002" }]`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"content": "My pic!\nhttps://foo.bar/image.jpg", "mobile": "250788383383", "pass": "Password", "user": "Username"}, SendPrep: setSendURL}, {Label: "Error Sending", MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, + ExpectedMsgStatus: "E", + MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, ExpectedPostParams: map[string]string{"content": `Error Message`, "mobile": "250788383383", "pass": "Password", "user": "Username"}, SendPrep: setSendURL}, } diff --git a/handlers/start/start_test.go b/handlers/start/start_test.go index a4e0f0b7e..d26a8c4c9 100644 --- a/handlers/start/start_test.go +++ b/handlers/start/start_test.go @@ -74,19 +74,19 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Hello World"), ExpectedURN: "tel:+250788123123", ExpectedDate: time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC)}, - {Label: "Receive Valid Encoded", URL: receiveURL, Data: validReceiveEncoded, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Encoded", URL: receiveURL, Data: validReceiveEncoded, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Кохання"), ExpectedURN: "tel:+380501529999", ExpectedDate: time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC)}, - {Label: "Receive Valid with empty Text", URL: receiveURL, Data: validReceiveEmptyText, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid with empty Text", URL: receiveURL, Data: validReceiveEmptyText, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp(""), ExpectedURN: "tel:+250788123123"}, - {Label: "Receive Valid missing body", URL: receiveURL, Data: validMissingBody, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid missing body", URL: receiveURL, Data: validMissingBody, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp(""), ExpectedURN: "tel:+250788123123"}, - {Label: "Receive invalidURN", URL: receiveURL, Data: invalidURNReceive, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Receive missing Request ID", URL: receiveURL, Data: missingRequestID, ExpectedStatus: 400, ExpectedResponse: "Error"}, - {Label: "Receive missing From", URL: receiveURL, Data: missingFrom, ExpectedStatus: 400, ExpectedResponse: "Error"}, - {Label: "Receive missing To", URL: receiveURL, Data: missingTo, ExpectedStatus: 400, ExpectedResponse: "Error"}, - {Label: "Invalid XML", URL: receiveURL, Data: notXML, ExpectedStatus: 400, ExpectedResponse: "Error"}, + {Label: "Receive invalidURN", URL: receiveURL, Data: invalidURNReceive, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, + {Label: "Receive missing Request ID", URL: receiveURL, Data: missingRequestID, ExpectedRespStatus: 400, ExpectedRespBody: "Error"}, + {Label: "Receive missing From", URL: receiveURL, Data: missingFrom, ExpectedRespStatus: 400, ExpectedRespBody: "Error"}, + {Label: "Receive missing To", URL: receiveURL, Data: missingTo, ExpectedRespStatus: 400, ExpectedRespBody: "Error"}, + {Label: "Invalid XML", URL: receiveURL, Data: notXML, ExpectedRespStatus: 400, ExpectedRespBody: "Error"}, } func TestHandler(t *testing.T) { @@ -106,7 +106,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "380502535130309161501", MockResponseBody: `380502535130309161501Accepted`, MockResponseStatus: 200, @@ -119,7 +119,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Long Send", MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "380502535130309161501", MockResponseBody: `380502535130309161501Accepted`, MockResponseStatus: 200, @@ -133,7 +133,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "My pic!", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MsgURN: "tel:+250788383383", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "380502535130309161501", MockResponseBody: `380502535130309161501Accepted`, MockResponseStatus: 200, @@ -146,7 +146,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Error Response", MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedExternalID: "", MockResponseBody: `This is an error`, MockResponseStatus: 200, @@ -158,8 +158,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL}, {Label: "Error Sending", MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `Error`, MockResponseStatus: 401, + ExpectedMsgStatus: "E", + MockResponseBody: `Error`, MockResponseStatus: 401, ExpectedHeaders: map[string]string{ "Content-Type": "application/xml; charset=utf8", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index 3ade8d0cf..b4f3d2e1b 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -452,49 +452,49 @@ var contactMsg = ` }` var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: helloMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Hello World"), ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Start Message", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: startMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedChannelEvent: courier.NewConversation, ExpectedURN: "telegram:3527065#nicpottier", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, + {Label: "Receive Start Message", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: startMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), ExpectedEvent: courier.NewConversation, ExpectedURN: "telegram:3527065#nicpottier", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive No Params", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: emptyMsg, ExpectedStatus: 200, ExpectedResponse: "Ignoring"}, + {Label: "Receive No Params", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: emptyMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Ignoring"}, - {Label: "Receive Invalid JSON", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: "foo", ExpectedStatus: 400, ExpectedResponse: "unable to parse"}, + {Label: "Receive Invalid JSON", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: "foo", ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse"}, - {Label: "Receive Sticker", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: stickerMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Sticker", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: stickerMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/sticker.jpg"}, ExpectedURN: "telegram:3527065", ExpectedExternalID: "44", ExpectedDate: time.Date(2016, 1, 30, 2, 07, 48, 0, time.UTC)}, - {Label: "Receive Photo", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: photoMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Photo", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: photoMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Photo Caption"), ExpectedAttachments: []string{"/file/bota123/photo.jpg"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "85", ExpectedDate: time.Date(2017, 5, 3, 20, 28, 38, 0, time.UTC)}, - {Label: "Receive Video", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: videoMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Video", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: videoMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/video.jpg"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "86", ExpectedDate: time.Date(2017, 5, 3, 20, 29, 24, 0, time.UTC)}, - {Label: "Receive Voice", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: voiceMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Voice", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: voiceMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/voice.mp4"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "91", ExpectedDate: time.Date(2017, 5, 3, 20, 50, 46, 0, time.UTC)}, - {Label: "Receive Document", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: documentMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Document", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: documentMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/document.xls"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "92", ExpectedDate: time.Date(2017, 5, 3, 20, 58, 20, 0, time.UTC)}, - {Label: "Receive Location", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: locationMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Location", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: locationMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("-2.890287,-79.004333"), ExpectedAttachments: []string{"geo:-2.890287,-79.004333"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "94", ExpectedDate: time.Date(2017, 5, 3, 21, 00, 44, 0, time.UTC)}, - {Label: "Receive Venue", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: venueMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Venue", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: venueMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Cuenca, Provincia del Azuay"), ExpectedAttachments: []string{"geo:-2.898944,-79.006835"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "95", ExpectedDate: time.Date(2017, 5, 3, 21, 05, 20, 0, time.UTC)}, - {Label: "Receive Contact", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: contactMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Contact", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: contactMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Adolf Taxi (0788531373)"), ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "96", ExpectedDate: time.Date(2017, 5, 3, 21, 9, 15, 0, time.UTC)}, - {Label: "Receive Empty", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: emptyMsg, ExpectedStatus: 200, ExpectedResponse: "Ignoring"}, + {Label: "Receive Empty", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: emptyMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Ignoring"}, - {Label: "Receive Invalid FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: invalidFileID, ExpectedStatus: 200, ExpectedResponse: "unable to resolve file"}, + {Label: "Receive Invalid FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: invalidFileID, ExpectedRespStatus: 200, ExpectedRespBody: "unable to resolve file"}, - {Label: "Receive NoOk FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: noOkFile, ExpectedStatus: 200, ExpectedResponse: "no 'ok' in response"}, + {Label: "Receive NoOk FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: noOkFile, ExpectedRespStatus: 200, ExpectedRespBody: "no 'ok' in response"}, - {Label: "Receive NotOk FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: notOkFile, ExpectedStatus: 200, ExpectedResponse: "not present"}, + {Label: "Receive NotOk FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: notOkFile, ExpectedRespStatus: 200, ExpectedRespBody: "not present"}, - {Label: "Receive No FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: noFile, ExpectedStatus: 200, ExpectedResponse: "result.file_path"}, + {Label: "Receive No FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: noFile, ExpectedRespStatus: 200, ExpectedRespBody: "result.file_path"}, } func buildMockTelegramService(testCases []ChannelHandleTestCase) *httptest.Server { @@ -578,7 +578,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "chat_id": "12345", "reply_markup": `{"remove_keyboard":true}`, }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "133", SendPrep: setSendURL, }, @@ -594,7 +594,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "chat_id": "12345", "reply_markup": `{"keyboard":[[{"text":"Yes"},{"text":"No"}]],"resize_keyboard":true,"one_time_keyboard":true}`, }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "133", SendPrep: setSendURL, }, @@ -611,7 +611,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "document": "https://foo.bar/document.pdf", "reply_markup": `{"keyboard":[[{"text":"Yes"},{"text":"No"}]],"resize_keyboard":true,"one_time_keyboard":true}`, }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "133", SendPrep: setSendURL, }, @@ -623,7 +623,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "☺", "chat_id": "12345"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "133", SendPrep: setSendURL, }, @@ -634,7 +634,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "ok": false }`, MockResponseStatus: 403, ExpectedPostParams: map[string]string{"text": `Error`, "chat_id": "12345"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -644,7 +644,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "ok": false, "error_code":403, "description":"Forbidden: bot was blocked by the user"}`, MockResponseStatus: 403, ExpectedPostParams: map[string]string{"text": `Stopped Contact`, "chat_id": "12345"}, - ExpectedStatus: "F", + ExpectedMsgStatus: "F", ExpectedStopEvent: true, SendPrep: setSendURL, }, @@ -659,8 +659,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ "chat_id": "12345", "reply_markup": `{"remove_keyboard":true}`, }, - ExpectedStatus: "E", - SendPrep: setSendURL, + ExpectedMsgStatus: "E", + SendPrep: setSendURL, }, { Label: "Send Photo", @@ -670,7 +670,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"caption": "My pic!", "chat_id": "12345", "photo": "https://foo.bar/image.jpg"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -681,7 +681,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"caption": "My vid!", "chat_id": "12345", "video": "https://foo.bar/video.mpeg"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -692,7 +692,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"caption": "My audio!", "chat_id": "12345", "audio": "https://foo.bar/audio.mp3"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -703,17 +703,17 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "ok": true, "result": { "message_id": 133 } }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"caption": "My document!", "chat_id": "12345", "document": "https://foo.bar/document.pdf"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { - Label: "Unknown Attachment", - MsgText: "My pic!", - MsgURN: "telegram:12345", - MsgAttachments: []string{"unknown/foo:https://foo.bar/unknown.foo"}, - ExpectedStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unknown attachment content type: unknown/foo", "")}, - SendPrep: setSendURL, + Label: "Unknown Attachment", + MsgText: "My pic!", + MsgURN: "telegram:12345", + MsgAttachments: []string{"unknown/foo:https://foo.bar/unknown.foo"}, + ExpectedMsgStatus: "E", + ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unknown attachment content type: unknown/foo", "")}, + SendPrep: setSendURL, }, } diff --git a/handlers/telesom/telesom_test.go b/handlers/telesom/telesom_test.go index c377032bf..c3dc5c30c 100644 --- a/handlers/telesom/telesom_test.go +++ b/handlers/telesom/telesom_test.go @@ -23,17 +23,17 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, - {Label: "Invalid URN", URL: invalidURN, Data: "", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "", ExpectedStatus: 400, ExpectedResponse: "field 'mobile' required"}, - {Label: "Receive No Sender", URL: receiveNoSender, Data: "", ExpectedStatus: 400, ExpectedResponse: "field 'mobile' required"}, + {Label: "Invalid URN", URL: invalidURN, Data: "", ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, + {Label: "Receive No Params", URL: receiveNoParams, Data: "", ExpectedRespStatus: 400, ExpectedRespBody: "field 'mobile' required"}, + {Label: "Receive No Sender", URL: receiveNoSender, Data: "", ExpectedRespStatus: 400, ExpectedRespBody: "field 'mobile' required"}, - {Label: "Receive Valid Message", URL: receiveNoParams, Data: "mobile=%2B2349067554729&msg=Join", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message", URL: receiveNoParams, Data: "mobile=%2B2349067554729&msg=Join", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, - {Label: "Invalid URN", URL: receiveNoParams, Data: "mobile=MTN&msg=Join", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedStatus: 400, ExpectedResponse: "field 'mobile' required"}, - {Label: "Receive No Sender", URL: receiveNoParams, Data: "msg=Join", ExpectedStatus: 400, ExpectedResponse: "field 'mobile' required"}, + {Label: "Invalid URN", URL: receiveNoParams, Data: "mobile=MTN&msg=Join", ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, + {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "field 'mobile' required"}, + {Label: "Receive No Sender", URL: receiveNoParams, Data: "msg=Join", ExpectedRespStatus: 400, ExpectedRespBody: "field 'mobile' required"}, } func TestHandler(t *testing.T) { @@ -54,29 +54,29 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", MsgText: "Simple Message", MsgURN: "tel:+252788383383", - ExpectedStatus: "W", - MockResponseBody: "Success", MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: "Success", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"msg": "Simple Message", "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "D69BB824F88F20482B94ECF3822EBD84"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, SendPrep: setSendURL}, {Label: "Unicode Send", MsgText: "☺", MsgURN: "tel:+252788383383", - ExpectedStatus: "W", - MockResponseBody: "Success", MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: "Success", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"msg": "☺", "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "60421A7D99BD79FE02697D567315AD0E"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, SendPrep: setSendURL}, {Label: "Error Sending", MsgText: "Error Message", MsgURN: "tel:+252788383383", - ExpectedStatus: "E", - MockResponseBody: "error", MockResponseStatus: 401, + ExpectedMsgStatus: "E", + MockResponseBody: "error", MockResponseStatus: 401, ExpectedURLParams: map[string]string{"msg": `Error Message`, "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "3F1E492B2186551570F24C2F07D5D7E2"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, SendPrep: setSendURL}, {Label: "Send Attachment", MsgText: "My pic!", MsgURN: "tel:+252788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: `Success`, MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: `Success`, MockResponseStatus: 200, ExpectedURLParams: map[string]string{"msg": "My pic!\nhttps://foo.bar/image.jpg", "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "DBE569579FD899628C17254ECCE15DB7"}, ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, SendPrep: setSendURL}, diff --git a/handlers/test.go b/handlers/test.go index a66552164..57e810791 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -29,16 +29,18 @@ type RequestPrepFunc func(*http.Request) // ChannelHandleTestCase defines the test values for a particular test case type ChannelHandleTestCase struct { - Label string - - URL string - Data string - Headers map[string]string - MultipartFormFields map[string]string + Label string + NoQueueErrorCheck bool + NoInvalidChannelCheck bool + PrepRequest RequestPrepFunc - ExpectedStatus int - ExpectedResponse string + URL string + Data string + Headers map[string]string + MultipartForm map[string]string + ExpectedRespStatus int + ExpectedRespBody string ExpectedContactName *string ExpectedMsgText *string ExpectedURN urns.URN @@ -48,14 +50,8 @@ type ChannelHandleTestCase struct { ExpectedMsgStatus courier.MsgStatusValue ExpectedExternalID string ExpectedMsgID int64 - - ExpectedChannelEvent courier.ChannelEventType - ExpectedChannelEventExtra map[string]interface{} - - NoQueueErrorCheck bool - NoInvalidChannelCheck bool - - PrepRequest RequestPrepFunc + ExpectedEvent courier.ChannelEventType + ExpectedEventExtra map[string]interface{} } // SendPrepFunc allows test cases to modify the channel, msg or server before a message is sent @@ -99,11 +95,9 @@ type ChannelSendTestCase struct { ExpectedPostParams map[string]string ExpectedRequestBody string ExpectedHeaders map[string]string - - ExpectedStatus string - ExpectedExternalID string - ExpectedErrors []courier.ChannelError - + ExpectedMsgStatus courier.MsgStatusValue + ExpectedExternalID string + ExpectedErrors []courier.ChannelError ExpectedStopEvent bool ExpectedContactURNs map[string]bool ExpectedNewURN string @@ -302,9 +296,9 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour require.Equal(tc.ExpectedExternalID, status.ExternalID()) } - if tc.ExpectedStatus != "" { + if tc.ExpectedMsgStatus != "" { require.NotNil(status, "status should not be nil") - require.Equal(tc.ExpectedStatus, string(status.Status())) + require.Equal(tc.ExpectedMsgStatus, status.Status()) } if tc.ExpectedStopEvent { @@ -355,7 +349,7 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri mb.Reset() - testHandlerRequest(t, s, tc.URL, tc.Headers, tc.Data, tc.MultipartFormFields, tc.ExpectedStatus, &tc.ExpectedResponse, tc.PrepRequest) + testHandlerRequest(t, s, tc.URL, tc.Headers, tc.Data, tc.MultipartForm, tc.ExpectedRespStatus, &tc.ExpectedRespBody, tc.PrepRequest) // pop our message off and test against it contactName := mb.GetLastContactName() @@ -363,7 +357,7 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri event, _ := mb.GetLastChannelEvent() status, _ := mb.GetLastMsgStatus() - if tc.ExpectedStatus == 200 { + if tc.ExpectedRespStatus == 200 { if tc.ExpectedContactName != nil { require.Equal(*tc.ExpectedContactName, contactName) } @@ -372,11 +366,11 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri require.Equal(mb.LenQueuedMsgs(), 1) require.Equal(*tc.ExpectedMsgText, msg.Text()) } - if tc.ExpectedChannelEvent != "" { - assert.Equal(t, tc.ExpectedChannelEvent, event.EventType()) + if tc.ExpectedEvent != "" { + assert.Equal(t, tc.ExpectedEvent, event.EventType()) } - if tc.ExpectedChannelEventExtra != nil { - require.Equal(tc.ExpectedChannelEventExtra, event.Extra()) + if tc.ExpectedEventExtra != nil { + require.Equal(tc.ExpectedEventExtra, event.Extra()) } if tc.ExpectedURN != "" { if msg != nil { @@ -429,7 +423,7 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri } // if we're expecting a message, status or event, check we have a log for it - if tc.ExpectedMsgText != nil || tc.ExpectedMsgStatus != "" || tc.ExpectedChannelEvent != "" { + if tc.ExpectedMsgText != nil || tc.ExpectedMsgStatus != "" || tc.ExpectedEvent != "" { assert.Greater(t, len(mb.ChannelLogs()), 0, "expected at least one channel log") } }) @@ -442,14 +436,14 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri t.Run("Queue Error", func(t *testing.T) { mb.SetErrorOnQueue(true) defer mb.SetErrorOnQueue(false) - testHandlerRequest(t, s, validCase.URL, validCase.Headers, validCase.Data, validCase.MultipartFormFields, 400, Sp("unable to queue message"), validCase.PrepRequest) + testHandlerRequest(t, s, validCase.URL, validCase.Headers, validCase.Data, validCase.MultipartForm, 400, Sp("unable to queue message"), validCase.PrepRequest) }) } if !validCase.NoInvalidChannelCheck { t.Run("Receive With Invalid Channel", func(t *testing.T) { mb.ClearChannels() - testHandlerRequest(t, s, validCase.URL, validCase.Headers, validCase.Data, validCase.MultipartFormFields, 400, Sp("channel not found"), validCase.PrepRequest) + testHandlerRequest(t, s, validCase.URL, validCase.Headers, validCase.Data, validCase.MultipartForm, 400, Sp("channel not found"), validCase.PrepRequest) }) } } @@ -469,7 +463,7 @@ func RunChannelBenchmarks(b *testing.B, channels []courier.Channel, handler cour b.Run(testCase.Label, func(b *testing.B) { for i := 0; i < b.N; i++ { - testHandlerRequest(b, s, testCase.URL, testCase.Headers, testCase.Data, testCase.MultipartFormFields, testCase.ExpectedStatus, nil, testCase.PrepRequest) + testHandlerRequest(b, s, testCase.URL, testCase.Headers, testCase.Data, testCase.MultipartForm, testCase.ExpectedRespStatus, nil, testCase.PrepRequest) } }) } diff --git a/handlers/thinq/thinq_test.go b/handlers/thinq/thinq_test.go index 92cfe031f..d5a7577cb 100644 --- a/handlers/thinq/thinq_test.go +++ b/handlers/thinq/thinq_test.go @@ -20,27 +20,27 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: "message=hello+world&from=2065551234&type=sms&to=2065551212", - ExpectedStatus: 200, - ExpectedResponse: "Accepted", - ExpectedMsgText: Sp("hello world"), - ExpectedURN: "tel:+12065551234", + Label: "Receive Valid", + URL: receiveURL, + Data: "message=hello+world&from=2065551234&type=sms&to=2065551212", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("hello world"), + ExpectedURN: "tel:+12065551234", }, { - Label: "Receive No Params", - URL: receiveURL, - Data: " ", - ExpectedStatus: 400, - ExpectedResponse: `'From' failed on the 'required'`, + Label: "Receive No Params", + URL: receiveURL, + Data: " ", + ExpectedRespStatus: 400, + ExpectedRespBody: `'From' failed on the 'required'`, }, { Label: "Receive Media", URL: receiveURL, Data: "message=http://foo.bar/foo.png&hello+world&from=2065551234&type=mms&to=2065551212", - ExpectedStatus: 200, - ExpectedResponse: "Accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", ExpectedURN: "tel:+12065551234", ExpectedAttachments: []string{"http://foo.bar/foo.png"}, }, @@ -49,25 +49,25 @@ var testCases = []ChannelHandleTestCase{ Label: "Status Valid", URL: statusURL, Data: "guid=1234&status=DELIVRD", - ExpectedStatus: 200, + ExpectedRespStatus: 200, ExpectedExternalID: "1234", - ExpectedResponse: `"status":"D"`, + ExpectedRespBody: `"status":"D"`, }, { Label: "Status Invalid", URL: statusURL, Data: "guid=1234&status=UN", - ExpectedStatus: 400, + ExpectedRespStatus: 400, ExpectedExternalID: "1234", - ExpectedResponse: `"unknown status: 'UN'"`, + ExpectedRespBody: `"unknown status: 'UN'"`, }, { Label: "Status Missing GUID", URL: statusURL, Data: "status=DELIVRD", - ExpectedStatus: 400, + ExpectedRespStatus: 400, ExpectedExternalID: "1234", - ExpectedResponse: `'GUID' failed on the 'required' tag`, + ExpectedRespBody: `'GUID' failed on the 'required' tag`, }, } @@ -89,7 +89,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedHeaders: map[string]string{"Authorization": "Basic dXNlcjE6c2VzYW1l"}, ExpectedRequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"Simple Message ☺"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -101,7 +101,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "guid": "1002" }`, MockResponseStatus: 200, ExpectedRequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"My pic!"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -112,7 +112,7 @@ var sendTestCases = []ChannelSendTestCase{ MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MockResponseBody: `{ "guid": "1002" }`, MockResponseStatus: 200, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -123,7 +123,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: `{}`, MockResponseStatus: 200, ExpectedRequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"No External ID"}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Unable to read external ID from guid field", "")}, SendPrep: setSendURL, }, @@ -134,7 +134,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, ExpectedRequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"Error Message"}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index d94be3518..dee7bdd91 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -76,160 +76,160 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: receiveValid, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Valid", URL: receiveURL, Data: receiveValid, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Receive Button Ignored", URL: receiveURL, Data: receiveButtonIgnored, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Button Ignored", URL: receiveURL, Data: receiveButtonIgnored, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Receive Invalid Signature", URL: receiveURL, Data: receiveValid, ExpectedStatus: 400, ExpectedResponse: "invalid request signature", + {Label: "Receive Invalid Signature", URL: receiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedRespBody: "invalid request signature", PrepRequest: addInvalidSignature}, - {Label: "Receive Missing Signature", URL: receiveURL, Data: receiveValid, ExpectedStatus: 400, ExpectedResponse: "missing request signature"}, - {Label: "Receive No Params", URL: receiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: "field 'messagesid' required", + {Label: "Receive Missing Signature", URL: receiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedRespBody: "missing request signature"}, + {Label: "Receive No Params", URL: receiveURL, Data: " ", ExpectedRespStatus: 400, ExpectedRespBody: "field 'messagesid' required", PrepRequest: addValidSignature}, - {Label: "Receive Media", URL: receiveURL, Data: receiveMedia, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Media", URL: receiveURL, Data: receiveMedia, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Media With Msg", URL: receiveURL, Data: receiveMediaWithMsg, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Media With Msg", URL: receiveURL, Data: receiveMediaWithMsg, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Base64", URL: receiveURL, Data: receiveBase64, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Base64", URL: receiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status Stop contact", URL: statusURL, Data: statusStop, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, + {Label: "Status Stop contact", URL: statusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, PrepRequest: addValidSignature}, - {Label: "Status No Params", URL: statusURL, Data: " ", ExpectedStatus: 200, ExpectedResponse: "no msg status, ignoring", + {Label: "Status No Params", URL: statusURL, Data: " ", ExpectedRespStatus: 200, ExpectedRespBody: "no msg status, ignoring", PrepRequest: addValidSignature}, - {Label: "Status Invalid Status", URL: statusURL, Data: statusInvalid, ExpectedStatus: 400, ExpectedResponse: "unknown status 'huh'", + {Label: "Status Invalid Status", URL: statusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: statusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status Valid", URL: statusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status Read", URL: statusURL, Data: statusRead, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status Read", URL: statusURL, Data: statusRead, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status ID Valid", URL: statusIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedMsgID: 12345, + {Label: "Status ID Valid", URL: statusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: statusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status ID Invalid", URL: statusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } var tmsTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: tmsReceiveURL, Data: receiveValid, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Valid", URL: tmsReceiveURL, Data: receiveValid, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Receive TMS extra", URL: tmsReceiveURL, Data: tmsReceiveExtra, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive TMS extra", URL: tmsReceiveURL, Data: tmsReceiveExtra, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("John Cruz"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMbbf29aeb9d380ce2a1c0ae4635ff9dab", PrepRequest: addValidSignature}, - {Label: "Receive Invalid Signature", URL: tmsReceiveURL, Data: receiveValid, ExpectedStatus: 400, ExpectedResponse: "invalid request signature", + {Label: "Receive Invalid Signature", URL: tmsReceiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedRespBody: "invalid request signature", PrepRequest: addInvalidSignature}, - {Label: "Receive Missing Signature", URL: tmsReceiveURL, Data: receiveValid, ExpectedStatus: 400, ExpectedResponse: "missing request signature"}, - {Label: "Receive No Params", URL: tmsReceiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: "field 'messagesid' required", + {Label: "Receive Missing Signature", URL: tmsReceiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedRespBody: "missing request signature"}, + {Label: "Receive No Params", URL: tmsReceiveURL, Data: " ", ExpectedRespStatus: 400, ExpectedRespBody: "field 'messagesid' required", PrepRequest: addValidSignature}, - {Label: "Receive Media", URL: tmsReceiveURL, Data: receiveMedia, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Media", URL: tmsReceiveURL, Data: receiveMedia, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Media With Msg", URL: tmsReceiveURL, Data: receiveMediaWithMsg, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Media With Msg", URL: tmsReceiveURL, Data: receiveMediaWithMsg, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Base64", URL: tmsReceiveURL, Data: receiveBase64, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Base64", URL: tmsReceiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status Stop contact", URL: tmsStatusURL, Data: statusStop, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, + {Label: "Status Stop contact", URL: tmsStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, PrepRequest: addValidSignature}, - {Label: "Status TMS extra", URL: tmsStatusURL, Data: tmsStatusExtra, ExpectedStatus: 200, ExpectedResponse: `"status":"S"`, + {Label: "Status TMS extra", URL: tmsStatusURL, Data: tmsStatusExtra, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, ExpectedExternalID: "SM0b6e2697aae04182a9f5b5c7a8994c7f", PrepRequest: addValidSignature}, - {Label: "Status No Params", URL: tmsStatusURL, Data: " ", ExpectedStatus: 200, ExpectedResponse: "no msg status, ignoring", + {Label: "Status No Params", URL: tmsStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedRespBody: "no msg status, ignoring", PrepRequest: addValidSignature}, - {Label: "Status Invalid Status", URL: tmsStatusURL, Data: statusInvalid, ExpectedStatus: 400, ExpectedResponse: "unknown status 'huh'", + {Label: "Status Invalid Status", URL: tmsStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: tmsStatusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status Valid", URL: tmsStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status ID Valid", URL: tmsStatusIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedMsgID: 12345, + {Label: "Status ID Valid", URL: tmsStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: tmsStatusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status ID Invalid", URL: tmsStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } var twTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: twReceiveURL, Data: receiveValid, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Valid", URL: twReceiveURL, Data: receiveValid, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, {Label: "Receive Forwarded Valid", URL: twReceiveURL, Data: receiveValid, - Headers: map[string]string{forwardedPathHeader: "/handlers/twilio/receive/8eb23e93-5ecb-45ba-b726-3b064e0c56ab"}, - ExpectedStatus: 200, ExpectedResponse: "", + Headers: map[string]string{forwardedPathHeader: "/handlers/twilio/receive/8eb23e93-5ecb-45ba-b726-3b064e0c56ab"}, + ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addForwardSignature}, - {Label: "Receive Invalid Signature", URL: twReceiveURL, Data: receiveValid, ExpectedStatus: 400, ExpectedResponse: "invalid request signature", + {Label: "Receive Invalid Signature", URL: twReceiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedRespBody: "invalid request signature", PrepRequest: addInvalidSignature}, - {Label: "Receive Missing Signature", URL: twReceiveURL, Data: receiveValid, ExpectedStatus: 400, ExpectedResponse: "missing request signature"}, - {Label: "Receive No Params", URL: twReceiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: "field 'messagesid' required", + {Label: "Receive Missing Signature", URL: twReceiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedRespBody: "missing request signature"}, + {Label: "Receive No Params", URL: twReceiveURL, Data: " ", ExpectedRespStatus: 400, ExpectedRespBody: "field 'messagesid' required", PrepRequest: addValidSignature}, - {Label: "Receive Media", URL: twReceiveURL, Data: receiveMedia, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Media", URL: twReceiveURL, Data: receiveMedia, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Media With Msg", URL: twReceiveURL, Data: receiveMediaWithMsg, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Media With Msg", URL: twReceiveURL, Data: receiveMediaWithMsg, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Base64", URL: twReceiveURL, Data: receiveBase64, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Base64", URL: twReceiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status Stop contact", URL: twStatusURL, Data: statusStop, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, + {Label: "Status Stop contact", URL: twStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, PrepRequest: addValidSignature}, - {Label: "Status No Params", URL: twStatusURL, Data: " ", ExpectedStatus: 200, ExpectedResponse: "no msg status, ignoring", + {Label: "Status No Params", URL: twStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedRespBody: "no msg status, ignoring", PrepRequest: addValidSignature}, - {Label: "Status Invalid Status", URL: twStatusURL, Data: statusInvalid, ExpectedStatus: 400, ExpectedResponse: "unknown status 'huh'", + {Label: "Status Invalid Status", URL: twStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: twStatusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status Valid", URL: twStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status ID Valid", URL: twStatusIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedMsgID: 12345, + {Label: "Status ID Valid", URL: twStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: twStatusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status ID Invalid", URL: twStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } var swTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: swReceiveURL, Data: receiveValid, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Valid", URL: swReceiveURL, Data: receiveValid, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, - {Label: "Receive No Params", URL: swReceiveURL, Data: " ", ExpectedStatus: 400, ExpectedResponse: "field 'messagesid' required"}, - {Label: "Receive Media", URL: swReceiveURL, Data: receiveMedia, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive No Params", URL: swReceiveURL, Data: " ", ExpectedRespStatus: 400, ExpectedRespBody: "field 'messagesid' required"}, + {Label: "Receive Media", URL: swReceiveURL, Data: receiveMedia, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}}, - {Label: "Receive Media With Msg", URL: swReceiveURL, Data: receiveMediaWithMsg, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Media With Msg", URL: swReceiveURL, Data: receiveMediaWithMsg, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}}, - {Label: "Receive Base64", URL: swReceiveURL, Data: receiveBase64, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Base64", URL: swReceiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, - {Label: "Status Stop contact", URL: swStatusURL, Data: statusStop, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, + {Label: "Status Stop contact", URL: swStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, PrepRequest: addValidSignature}, - {Label: "Status No Params", URL: swStatusURL, Data: " ", ExpectedStatus: 200, ExpectedResponse: "no msg status, ignoring"}, - {Label: "Status Invalid Status", URL: swStatusURL, Data: statusInvalid, ExpectedStatus: 400, ExpectedResponse: "unknown status 'huh'"}, - {Label: "Status Valid", URL: swStatusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, - {Label: "Status ID Valid", URL: swStatusIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedMsgID: 12345}, - {Label: "Status ID Invalid", URL: swStatusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, + {Label: "Status No Params", URL: swStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedRespBody: "no msg status, ignoring"}, + {Label: "Status Invalid Status", URL: swStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status 'huh'"}, + {Label: "Status Valid", URL: swStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, + {Label: "Status ID Valid", URL: swStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgID: 12345}, + {Label: "Status ID Invalid", URL: swStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, } var waTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: waReceiveValid, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Valid", URL: receiveURL, Data: waReceiveValid, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "whatsapp:14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } var twaTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: twaReceiveURL, Data: waReceiveValid, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Valid", URL: twaReceiveURL, Data: waReceiveValid, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "whatsapp:14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Receive Valid", URL: twaReceiveURL, Data: waReceiveButtonValid, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Valid", URL: twaReceiveURL, Data: waReceiveButtonValid, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Confirm"), ExpectedURN: "whatsapp:14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Receive Prefixless URN", URL: twaReceiveURL, Data: waReceivePrefixlessURN, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Prefixless URN", URL: twaReceiveURL, Data: waReceivePrefixlessURN, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "whatsapp:14133881111", ExpectedExternalID: "SM681a1f26d9ec591431ce406e8f399525", PrepRequest: addValidSignature}, - {Label: "Status No Params", URL: twaStatusURL, Data: " ", ExpectedStatus: 200, ExpectedResponse: "no msg status, ignoring", + {Label: "Status No Params", URL: twaStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedRespBody: "no msg status, ignoring", PrepRequest: addValidSignature}, - {Label: "Status Invalid Status", URL: twaStatusURL, Data: statusInvalid, ExpectedStatus: 400, ExpectedResponse: "unknown status 'huh'", + {Label: "Status Invalid Status", URL: twaStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: twaStatusURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status Valid", URL: twaStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status ID Valid", URL: twaStatusIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedMsgID: 12345, + {Label: "Status ID Valid", URL: twaStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: twaStatusInvalidIDURL, Data: statusValid, ExpectedStatus: 200, ExpectedResponse: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status ID Invalid", URL: twaStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } @@ -300,7 +300,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Simple Message ☺", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedRequestPath: "/2010-04-01/Accounts/accountSID/Messages.json", ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -313,7 +313,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "I need to keep adding more things to make it work", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedRequestPath: "/2010-04-01/Accounts/accountSID/Messages.json", ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -324,7 +324,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "error": "out of credits" }`, MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, @@ -335,7 +335,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "code": 1001 }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, @@ -347,7 +347,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 400, ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStopEvent: true, - ExpectedStatus: "F", + ExpectedMsgStatus: "F", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, SendPrep: setSendURL, }, @@ -358,7 +358,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, @@ -370,7 +370,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "sid": "1002" }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "My pic!", "To": "+250788383383", "MediaUrl": "https://foo.bar/image.jpg", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } @@ -385,7 +385,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Simple Message ☺", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedRequestPath: "/2010-04-01/Accounts/accountSID/Messages.json", ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -398,7 +398,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "I need to keep adding more things to make it work", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedRequestPath: "/2010-04-01/Accounts/accountSID/Messages.json", ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -409,7 +409,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "error": "out of credits" }`, MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, @@ -420,7 +420,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "code": 1001 }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, @@ -432,7 +432,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 400, ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedStopEvent: true, - ExpectedStatus: "F", + ExpectedMsgStatus: "F", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, SendPrep: setSendURL, }, @@ -443,7 +443,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, @@ -455,7 +455,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "sid": "1002" }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "My pic!", "To": "+250788383383", "MediaUrl": "https://foo.bar/image.jpg", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } @@ -470,7 +470,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Simple Message ☺", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedRequestPath: "/2010-04-01/Accounts/accountSID/Messages.json", ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -483,7 +483,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "I need to keep adding more things to make it work", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedRequestPath: "/2010-04-01/Accounts/accountSID/Messages.json", ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -494,7 +494,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "error": "out of credits" }`, MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, @@ -505,7 +505,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "code": 1001 }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, @@ -516,7 +516,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "code": 21610 }`, MockResponseStatus: 400, ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - ExpectedStatus: "F", + ExpectedMsgStatus: "F", ExpectedStopEvent: true, ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, SendPrep: setSendURL, @@ -528,7 +528,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, @@ -540,7 +540,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "sid": "1002" }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "My pic!", "To": "+250788383383", "MediaUrl": "https://foo.bar/image.jpg", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } @@ -555,7 +555,7 @@ var swSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Simple Message ☺", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedRequestPath: "/2010-04-01/Accounts/accountSID/Messages.json", ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -568,7 +568,7 @@ var swSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "I need to keep adding more things to make it work", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedRequestPath: "/2010-04-01/Accounts/accountSID/Messages.json", ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -579,7 +579,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "error": "out of credits" }`, MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, @@ -590,7 +590,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "code": 1001 }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, @@ -601,7 +601,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "code": 21610 }`, MockResponseStatus: 400, ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - ExpectedStatus: "F", + ExpectedMsgStatus: "F", ExpectedStopEvent: true, ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, SendPrep: setSendURL, @@ -613,7 +613,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, @@ -625,7 +625,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "sid": "1002" }`, MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "My pic!", "To": "+250788383383", "MediaUrl": "https://foo.bar/image.jpg", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } @@ -639,7 +639,7 @@ var waSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Simple Message ☺", "To": "whatsapp:+250788383383", "From": "whatsapp:+12065551212", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, @@ -654,7 +654,7 @@ var twaSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Simple Message ☺", "To": "whatsapp:+250788383383", "From": "whatsapp:+12065551212", "StatusCallback": "https://localhost/c/twa/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedHeaders: map[string]string{"Authorization": "Basic YWNjb3VudFNJRDphdXRoVG9rZW4="}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "1002", SendPrep: setSendURL, }, diff --git a/handlers/twitter/twitter_test.go b/handlers/twitter/twitter_test.go index eea5ef134..39119b7ab 100644 --- a/handlers/twitter/twitter_test.go +++ b/handlers/twitter/twitter_test.go @@ -167,17 +167,17 @@ var attachment = `{ var notJSON = `blargh` var testCases = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Message", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: helloMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedContactName: Sp("Nicolas Pottier"), ExpectedURN: "twitterid:272953809#nicpottier", ExpectedMsgText: Sp("Hello World & good wishes."), ExpectedExternalID: "958501034212564996", ExpectedDate: time.Date(2018, 1, 31, 0, 43, 49, 301000000, time.UTC)}, - {Label: "Receive Attachment", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: attachment, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Attachment", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: attachment, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Hello"), ExpectedAttachments: []string{"https://image.foo.com/image.jpg"}, ExpectedURN: "twitterid:272953809#nicpottier", ExpectedExternalID: "958501034212564996", ExpectedDate: time.Date(2018, 1, 31, 0, 43, 49, 301000000, time.UTC)}, - {Label: "Not JSON", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "Error"}, - {Label: "Invalid Twitter handle", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidTwitterHandle, ExpectedStatus: 400, ExpectedResponse: "invalid twitter handle"}, - {Label: "Invalid Twitter ID", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidTwitterID, ExpectedStatus: 400, ExpectedResponse: "invalid twitter id"}, + {Label: "Not JSON", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "Error"}, + {Label: "Invalid Twitter handle", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidTwitterHandle, ExpectedRespStatus: 400, ExpectedRespBody: "invalid twitter handle"}, + {Label: "Invalid Twitter ID", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidTwitterID, ExpectedRespStatus: 400, ExpectedRespBody: "invalid twitter id"}, - {Label: "Webhook Verification", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?crc_token=test+token", ExpectedStatus: 200, ExpectedResponse: "sha256=O5hJl2njQRIa4vsumZ+3oom9ECR5m3aQLRZkPoYelp0="}, - {Label: "Webhook Verification Error", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", ExpectedStatus: 400, ExpectedResponse: "missing required 'crc_token'"}, + {Label: "Webhook Verification", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?crc_token=test+token", ExpectedRespStatus: 200, ExpectedRespBody: "sha256=O5hJl2njQRIa4vsumZ+3oom9ECR5m3aQLRZkPoYelp0="}, + {Label: "Webhook Verification Error", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", ExpectedRespStatus: 400, ExpectedRespBody: "missing required 'crc_token'"}, } func TestHandler(t *testing.T) { @@ -203,7 +203,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestPath: "/1.1/direct_messages/events/new.json", ExpectedRequestBody: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"Simple Message"}}}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "133", SendPrep: setSendURL, }, @@ -215,7 +215,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"event": { "id": "133"}}`, MockResponseStatus: 200, ExpectedRequestBody: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"Are you happy?","quick_reply":{"type":"options","options":[{"label":"Yes"},{"label":"No, but a really long no that is unr"}]}}}}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "133", SendPrep: setSendURL, }, @@ -251,7 +251,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"","attachment":{"type":"media","media":{"id":"710511363345354753"}}}}}}`, }: httpx.NewMockResponse(200, nil, []byte(`{"event": { "id": "133"}}`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "133", SendPrep: setSendURL, }, @@ -287,7 +287,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"","attachment":{"type":"media","media":{"id":"710511363345354753"}}}}}}`, }: httpx.NewMockResponse(200, nil, []byte(`{"event": { "id": "133"}}`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "133", SendPrep: setSendURL, }, @@ -323,7 +323,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Body: `{"event":{"type":"message_create","message_create":{"target":{"recipient_id":"12345"},"message_data":{"text":"","attachment":{"type":"media","media":{"id":"710511363345354753"}}}}}}`, }: httpx.NewMockResponse(200, nil, []byte(`{"event": { "id": "133"}}`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "133", SendPrep: setSendURL, }, @@ -344,7 +344,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ BodyContains: `"text":"http`, // audio link send as text }: httpx.NewMockResponse(200, nil, []byte(`{"event": { "id": "133"}}`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "133", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to upload media, unsupported Twitter attachment", "")}, SendPrep: setSendURL, @@ -355,7 +355,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "twitterid:12345", MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, SendPrep: setSendURL, }, @@ -365,7 +365,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "twitterid:12345", MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 403, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index 500719c0b..a9f2d72cf 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -53,7 +53,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -64,7 +64,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"I need to keep adding more things to make it work","type":"text","tracking_data":"10"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL}, { Label: "Unicode Send", @@ -74,7 +74,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"☺","type":"text","tracking_data":"10"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -86,7 +86,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Are you happy?","type":"text","tracking_data":"10","keyboard":{"Type":"keyboard","DefaultHeight":false,"Buttons":[{"ActionType":"reply","ActionBody":"Yes","Text":"Yes","TextSize":"regular","Columns":"3"},{"ActionType":"reply","ActionBody":"No","Text":"No","TextSize":"regular","Columns":"3"}]}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -98,7 +98,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"My pic!","type":"picture","tracking_data":"10","media":"{{ SERVER_URL }}/image.jpg"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -110,7 +110,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Text description is longer that 10 characters","type":"text","tracking_data":"10"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -122,7 +122,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"My video!","type":"text","tracking_data":"10"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -134,7 +134,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"My audio!","type":"text","tracking_data":"10"}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, { @@ -145,7 +145,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"status":3,"status_message":"InvalidToken"}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received non-0 status: '3'", "")}, SendPrep: setSendURL, }, @@ -157,7 +157,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `invalidJSON`, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received invalid JSON response", "")}, SendPrep: setSendURL, }, @@ -169,7 +169,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"status":"5"}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Error Message","type":"text","tracking_data":"10"}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } @@ -190,7 +190,7 @@ var buttonLayoutSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, MockResponseBody: `{"status":0,"status_message":"ok","message_token":4987381194038857789}`, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Select a, b, c or d.","type":"text","tracking_data":"10","keyboard":{"Type":"keyboard","DefaultHeight":false,"Buttons":[{"ActionType":"reply","ActionBody":"a","Text":"\u003cfont color=\"#ffffff\"\u003ea\u003c/font\u003e\u003cbr\u003e\u003cbr\u003e","TextSize":"large","Columns":"2","BgColor":"#f7bb3f"},{"ActionType":"reply","ActionBody":"b","Text":"\u003cfont color=\"#ffffff\"\u003eb\u003c/font\u003e\u003cbr\u003e\u003cbr\u003e","TextSize":"large","Columns":"2","BgColor":"#f7bb3f"},{"ActionType":"reply","ActionBody":"c","Text":"\u003cfont color=\"#ffffff\"\u003ec\u003c/font\u003e\u003cbr\u003e\u003cbr\u003e","TextSize":"large","Columns":"2","BgColor":"#f7bb3f"},{"ActionType":"reply","ActionBody":"d","Text":"\u003cfont color=\"#ffffff\"\u003ed\u003c/font\u003e\u003cbr\u003e\u003cbr\u003e","TextSize":"large","Columns":"6","BgColor":"#f7bb3f"}]}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", SendPrep: setSendURL, }, } @@ -481,51 +481,51 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("incoming msg"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", PrepRequest: addValidSignature}, - {Label: "Receive invalid signature", URL: receiveURL, Data: validMsg, ExpectedStatus: 400, ExpectedResponse: "invalid request signature", + {Label: "Receive invalid signature", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 400, ExpectedRespBody: "invalid request signature", PrepRequest: addInvalidSignature}, - {Label: "Receive invalid JSON", URL: receiveURL, Data: invalidJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON", + {Label: "Receive invalid JSON", URL: receiveURL, Data: invalidJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON", PrepRequest: addValidSignature}, - {Label: "Receive invalid URN", URL: receiveURL, Data: invalidURNMsg, ExpectedStatus: 400, ExpectedResponse: "invalid viber id", + {Label: "Receive invalid URN", URL: receiveURL, Data: invalidURNMsg, ExpectedRespStatus: 400, ExpectedRespBody: "invalid viber id", PrepRequest: addValidSignature}, - {Label: "Receive invalid Message Type", URL: receiveURL, Data: receiveInvalidMessageType, ExpectedStatus: 400, ExpectedResponse: "unknown message type", + {Label: "Receive invalid Message Type", URL: receiveURL, Data: receiveInvalidMessageType, ExpectedRespStatus: 400, ExpectedRespBody: "unknown message type", PrepRequest: addValidSignature}, - {Label: "Webhook validation", URL: receiveURL, Data: webhookCheck, ExpectedStatus: 200, ExpectedResponse: "webhook valid", PrepRequest: addValidSignature}, - {Label: "Failed Status Report", URL: receiveURL, Data: failedStatusReport, ExpectedStatus: 200, ExpectedResponse: `"status":"F"`, PrepRequest: addValidSignature}, - {Label: "Delivered Status Report", URL: receiveURL, Data: deliveredStatusReport, ExpectedStatus: 200, ExpectedResponse: `Ignored`, PrepRequest: addValidSignature}, - {Label: "Subcribe", URL: receiveURL, Data: validSubscribed, ExpectedStatus: 200, ExpectedResponse: "Accepted", PrepRequest: addValidSignature}, - {Label: "Subcribe Invalid URN", URL: receiveURL, Data: invalidURNSubscribed, ExpectedStatus: 400, ExpectedResponse: "invalid viber id", PrepRequest: addValidSignature}, - {Label: "Unsubcribe", URL: receiveURL, Data: validUnsubscribed, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedChannelEvent: courier.StopContact, PrepRequest: addValidSignature}, - {Label: "Unsubcribe Invalid URN", URL: receiveURL, Data: invalidURNUnsubscribed, ExpectedStatus: 400, ExpectedResponse: "invalid viber id", PrepRequest: addValidSignature}, - {Label: "Conversation Started", URL: receiveURL, Data: validConversationStarted, ExpectedStatus: 200, ExpectedResponse: "ignored conversation start", PrepRequest: addValidSignature}, - {Label: "Unexpected event", URL: receiveURL, Data: unexpectedEvent, ExpectedStatus: 400, - ExpectedResponse: "not handled, unknown event: unexpected", PrepRequest: addValidSignature}, - {Label: "Message missing text", URL: receiveURL, Data: rejectedMessage, ExpectedStatus: 400, ExpectedResponse: "missing text or media in message in request body", PrepRequest: addValidSignature}, - {Label: "Picture missing media", URL: receiveURL, Data: rejectedPicture, ExpectedStatus: 400, ExpectedResponse: "missing text or media in message in request body", PrepRequest: addValidSignature}, - {Label: "Video missing media", URL: receiveURL, Data: rejectedVideo, ExpectedStatus: 400, ExpectedResponse: "missing text or media in message in request body", PrepRequest: addValidSignature}, - - {Label: "Valid Contact receive", URL: receiveURL, Data: validReceiveContact, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Webhook validation", URL: receiveURL, Data: webhookCheck, ExpectedRespStatus: 200, ExpectedRespBody: "webhook valid", PrepRequest: addValidSignature}, + {Label: "Failed Status Report", URL: receiveURL, Data: failedStatusReport, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, PrepRequest: addValidSignature}, + {Label: "Delivered Status Report", URL: receiveURL, Data: deliveredStatusReport, ExpectedRespStatus: 200, ExpectedRespBody: `Ignored`, PrepRequest: addValidSignature}, + {Label: "Subcribe", URL: receiveURL, Data: validSubscribed, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", PrepRequest: addValidSignature}, + {Label: "Subcribe Invalid URN", URL: receiveURL, Data: invalidURNSubscribed, ExpectedRespStatus: 400, ExpectedRespBody: "invalid viber id", PrepRequest: addValidSignature}, + {Label: "Unsubcribe", URL: receiveURL, Data: validUnsubscribed, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedEvent: courier.StopContact, PrepRequest: addValidSignature}, + {Label: "Unsubcribe Invalid URN", URL: receiveURL, Data: invalidURNUnsubscribed, ExpectedRespStatus: 400, ExpectedRespBody: "invalid viber id", PrepRequest: addValidSignature}, + {Label: "Conversation Started", URL: receiveURL, Data: validConversationStarted, ExpectedRespStatus: 200, ExpectedRespBody: "ignored conversation start", PrepRequest: addValidSignature}, + {Label: "Unexpected event", URL: receiveURL, Data: unexpectedEvent, ExpectedRespStatus: 400, + ExpectedRespBody: "not handled, unknown event: unexpected", PrepRequest: addValidSignature}, + {Label: "Message missing text", URL: receiveURL, Data: rejectedMessage, ExpectedRespStatus: 400, ExpectedRespBody: "missing text or media in message in request body", PrepRequest: addValidSignature}, + {Label: "Picture missing media", URL: receiveURL, Data: rejectedPicture, ExpectedRespStatus: 400, ExpectedRespBody: "missing text or media in message in request body", PrepRequest: addValidSignature}, + {Label: "Video missing media", URL: receiveURL, Data: rejectedVideo, ExpectedRespStatus: 400, ExpectedRespBody: "missing text or media in message in request body", PrepRequest: addValidSignature}, + + {Label: "Valid Contact receive", URL: receiveURL, Data: validReceiveContact, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Alex: +12067799191"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", PrepRequest: addValidSignature}, - {Label: "Valid URL receive", URL: receiveURL, Data: validReceiveURL, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Valid URL receive", URL: receiveURL, Data: validReceiveURL, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("http://foo.com/"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", PrepRequest: addValidSignature}, - {Label: "Valid Location receive", URL: receiveURL, Data: validReceiveLocation, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Valid Location receive", URL: receiveURL, Data: validReceiveLocation, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("incoming msg"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, PrepRequest: addValidSignature}, - {Label: "Valid Sticker", URL: receiveURL, Data: validSticker, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Valid Sticker", URL: receiveURL, Data: validSticker, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("incoming msg"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", ExpectedAttachments: []string{"https://viber.github.io/docs/img/stickers/40133.png"}, PrepRequest: addValidSignature}, } var testWelcomeMessageCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("incoming msg"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", PrepRequest: addValidSignature}, - {Label: "Conversation Started", URL: receiveURL, Data: validConversationStarted, ExpectedStatus: 200, ExpectedResponse: `{"auth_token":"Token","text":"Welcome to VP, Please subscribe here for more.","type":"text","tracking_data":"0"}`, PrepRequest: addValidSignature}, + {Label: "Conversation Started", URL: receiveURL, Data: validConversationStarted, ExpectedRespStatus: 200, ExpectedRespBody: `{"auth_token":"Token","text":"Welcome to VP, Please subscribe here for more.","type":"text","tracking_data":"0"}`, PrepRequest: addValidSignature}, } func addValidSignature(r *http.Request) { diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index ebb795be0..bc1c239c1 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -234,8 +234,8 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive Message", URL: receiveURL, Data: msgHelloWorld, - ExpectedStatus: 200, - ExpectedResponse: "ok", + ExpectedRespStatus: 200, + ExpectedRespBody: "ok", ExpectedURN: "vk:123456", ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), @@ -244,8 +244,8 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive Empty Message", URL: receiveURL, Data: msgEmpty, - ExpectedStatus: 400, - ExpectedResponse: "no text or attachment", + ExpectedRespStatus: 400, + ExpectedRespBody: "no text or attachment", ExpectedURN: "vk:123456", ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), @@ -254,8 +254,8 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive First Photo Attachment", URL: receiveURL, Data: msgFirstPhotoAttachment, - ExpectedStatus: 200, - ExpectedResponse: "ok", + ExpectedRespStatus: 200, + ExpectedRespBody: "ok", ExpectedURN: "vk:123456", ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), @@ -265,8 +265,8 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive First Graffiti Attachment", URL: receiveURL, Data: msgFirstGraffitiAttachment, - ExpectedStatus: 200, - ExpectedResponse: "ok", + ExpectedRespStatus: 200, + ExpectedRespBody: "ok", ExpectedURN: "vk:123456", ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), @@ -276,8 +276,8 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive First Sticker Attachment", URL: receiveURL, Data: msgFirstStickerAttachment, - ExpectedStatus: 200, - ExpectedResponse: "ok", + ExpectedRespStatus: 200, + ExpectedRespBody: "ok", ExpectedURN: "vk:123456", ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), @@ -287,8 +287,8 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive First Audio Attachment", URL: receiveURL, Data: msgFirstAudioAttachment, - ExpectedStatus: 200, - ExpectedResponse: "ok", + ExpectedRespStatus: 200, + ExpectedRespBody: "ok", ExpectedURN: "vk:123456", ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), @@ -298,8 +298,8 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive First Audio Attachment", URL: receiveURL, Data: msgFirstDocAttachment, - ExpectedStatus: 200, - ExpectedResponse: "ok", + ExpectedRespStatus: 200, + ExpectedRespBody: "ok", ExpectedURN: "vk:123456", ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), @@ -309,8 +309,8 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive Message Keyboard", URL: receiveURL, Data: msgKeyboard, - ExpectedStatus: 200, - ExpectedResponse: "ok", + ExpectedRespStatus: 200, + ExpectedRespBody: "ok", ExpectedURN: "vk:123456", ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), @@ -319,33 +319,33 @@ var testCases = []ChannelHandleTestCase{ Label: "Receive Geolocation Attachment", URL: receiveURL, Data: msgGeolocationOnly, - ExpectedStatus: 200, - ExpectedResponse: "ok", + ExpectedRespStatus: 200, + ExpectedRespBody: "ok", ExpectedURN: "vk:123456", ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), ExpectedAttachments: []string{"geo:-9.652278,-35.701095"}, }, { - Label: "Validate secret", - URL: receiveURL, - Data: eventWithSecret, - ExpectedStatus: 200, - ExpectedResponse: "no message or server verification event", + Label: "Validate secret", + URL: receiveURL, + Data: eventWithSecret, + ExpectedRespStatus: 200, + ExpectedRespBody: "no message or server verification event", }, { - Label: "Invalidate secret", - URL: receiveURL, - Data: eventWithoutSecret, - ExpectedStatus: 400, - ExpectedResponse: "wrong secret key", + Label: "Invalidate secret", + URL: receiveURL, + Data: eventWithoutSecret, + ExpectedRespStatus: 400, + ExpectedRespBody: "wrong secret key", }, { - Label: "Verify server", - URL: receiveURL, - Data: eventServerVerification, - ExpectedStatus: 200, - ExpectedResponse: "a1b2c3", + Label: "Verify server", + URL: receiveURL, + Data: eventServerVerification, + ExpectedRespStatus: 200, + ExpectedRespBody: "a1b2c3", }, } @@ -394,7 +394,7 @@ var sendTestCases = []ChannelSendTestCase{ Label: "Send simple message", MsgText: "Simple message", MsgURN: "vk:123456789", - ExpectedStatus: "S", + ExpectedMsgStatus: "S", SendPrep: setSendURL, ExpectedExternalID: "1", MockResponses: map[MockedRequest]*httpx.MockResponse{ @@ -410,7 +410,7 @@ var sendTestCases = []ChannelSendTestCase{ MsgText: "", MsgURN: "vk:123456789", MsgAttachments: []string{"image/png:https://foo.bar/image.png"}, - ExpectedStatus: "S", + ExpectedMsgStatus: "S", SendPrep: setSendURL, ExpectedExternalID: "1", MockResponses: map[MockedRequest]*httpx.MockResponse{ @@ -436,7 +436,7 @@ var sendTestCases = []ChannelSendTestCase{ MsgText: "Attachments", MsgURN: "vk:123456789", MsgAttachments: []string{"image/png:https://foo.bar/image.png", "audio/mp3:https://foo.bar/audio.mp3"}, - ExpectedStatus: "S", + ExpectedMsgStatus: "S", SendPrep: setSendURL, ExpectedExternalID: "1", MockResponses: map[MockedRequest]*httpx.MockResponse{ @@ -462,7 +462,7 @@ var sendTestCases = []ChannelSendTestCase{ MsgText: "Send keyboard", MsgURN: "vk:123456789", MsgQuickReplies: []string{"A", "B", "C", "D", "E"}, - ExpectedStatus: "S", + ExpectedMsgStatus: "S", SendPrep: setSendURL, ExpectedExternalID: "1", MockResponses: map[MockedRequest]*httpx.MockResponse{ diff --git a/handlers/wavy/wavy_test.go b/handlers/wavy/wavy_test.go index ade4f3de1..a91c5f577 100644 --- a/handlers/wavy/wavy_test.go +++ b/handlers/wavy/wavy_test.go @@ -79,20 +79,20 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + {Label: "Receive Message", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", ExpectedMsgText: Sp("Eu quero pizza"), ExpectedURN: "tel:+5516981562820", ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)}, - {Label: "Invalid JSON receive", URL: receiveURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, - {Label: "Missing Keys receive", URL: receiveURL, Data: missingRequiredKeys, ExpectedStatus: 400, ExpectedResponse: "validation for 'ID' failed on the 'required'"}, - - {Label: "Sent Status Valid", URL: sentStatusURL, Data: validSentStatus, ExpectedStatus: 200, ExpectedResponse: "Status Update Accepted", ExpectedMsgStatus: courier.MsgSent}, - {Label: "Unknown Sent Status Valid", URL: sentStatusURL, Data: unknownSentStatus, ExpectedStatus: 400, ExpectedResponse: "unknown sent status code", ExpectedMsgStatus: courier.MsgWired}, - {Label: "Invalid JSON sent Status", URL: sentStatusURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, - {Label: "Missing Keys sent Status", URL: sentStatusURL, Data: missingRequiredKeys, ExpectedStatus: 400, ExpectedResponse: "validation for 'CollerationID' failed on the 'required'"}, - - {Label: "Delivered Status Valid", URL: deliveredStatusURL, Data: validDeliveredStatus, ExpectedStatus: 200, ExpectedResponse: "Status Update Accepted", ExpectedMsgStatus: courier.MsgDelivered}, - {Label: "Unknown Delivered Status Valid", URL: deliveredStatusURL, Data: unknownDeliveredStatus, ExpectedStatus: 400, ExpectedResponse: "unknown delivered status code", ExpectedMsgStatus: courier.MsgSent}, - {Label: "Invalid JSON delivered Statu", URL: deliveredStatusURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, - {Label: "Missing Keys sent Status", URL: deliveredStatusURL, Data: missingRequiredKeys, ExpectedStatus: 400, ExpectedResponse: "validation for 'CollerationID' failed on the 'required'"}, + {Label: "Invalid JSON receive", URL: receiveURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, + {Label: "Missing Keys receive", URL: receiveURL, Data: missingRequiredKeys, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'ID' failed on the 'required'"}, + + {Label: "Sent Status Valid", URL: sentStatusURL, Data: validSentStatus, ExpectedRespStatus: 200, ExpectedRespBody: "Status Update Accepted", ExpectedMsgStatus: courier.MsgSent}, + {Label: "Unknown Sent Status Valid", URL: sentStatusURL, Data: unknownSentStatus, ExpectedRespStatus: 400, ExpectedRespBody: "unknown sent status code", ExpectedMsgStatus: courier.MsgWired}, + {Label: "Invalid JSON sent Status", URL: sentStatusURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, + {Label: "Missing Keys sent Status", URL: sentStatusURL, Data: missingRequiredKeys, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'CollerationID' failed on the 'required'"}, + + {Label: "Delivered Status Valid", URL: deliveredStatusURL, Data: validDeliveredStatus, ExpectedRespStatus: 200, ExpectedRespBody: "Status Update Accepted", ExpectedMsgStatus: courier.MsgDelivered}, + {Label: "Unknown Delivered Status Valid", URL: deliveredStatusURL, Data: unknownDeliveredStatus, ExpectedRespStatus: 400, ExpectedRespBody: "unknown delivered status code", ExpectedMsgStatus: courier.MsgSent}, + {Label: "Invalid JSON delivered Statu", URL: deliveredStatusURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, + {Label: "Missing Keys sent Status", URL: deliveredStatusURL, Data: missingRequiredKeys, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'CollerationID' failed on the 'required'"}, } func TestHandler(t *testing.T) { @@ -110,7 +110,7 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var defaultSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "external1", MockResponseBody: `{"id": "external1"}`, MockResponseStatus: 200, @@ -119,13 +119,13 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL}, {Label: "Error status 403", MsgText: "Error Response", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedRequestBody: `{"destination":"250788383383","messageText":"Error Response"}`, MockResponseStatus: 403, SendPrep: setSendURL}, {Label: "Error Sending", MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: `Bad Gateway`, MockResponseStatus: 501, + ExpectedMsgStatus: "E", + MockResponseBody: `Bad Gateway`, MockResponseStatus: 501, SendPrep: setSendURL}, } diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index d42f8f59a..46fba5537 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -143,27 +143,27 @@ func addInvalidSignature(r *http.Request) { } var testCases = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Simple Message"), ExpectedURN: "wechat:1234", ExpectedExternalID: "123456", ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, - {Label: "Missing params", URL: receiveURL, Data: missingParamsRequired, ExpectedStatus: 400, ExpectedResponse: "Error:Field validation"}, - {Label: "Missing params Event or MsgId", URL: receiveURL, Data: missingParams, ExpectedStatus: 400, ExpectedResponse: "missing parameters, must have either 'MsgId' or 'Event'"}, + {Label: "Missing params", URL: receiveURL, Data: missingParamsRequired, ExpectedRespStatus: 400, ExpectedRespBody: "Error:Field validation"}, + {Label: "Missing params Event or MsgId", URL: receiveURL, Data: missingParams, ExpectedRespStatus: 400, ExpectedRespBody: "missing parameters, must have either 'MsgId' or 'Event'"}, - {Label: "Receive Image", URL: receiveURL, Data: imageMessage, ExpectedStatus: 200, ExpectedResponse: "", + {Label: "Receive Image", URL: receiveURL, Data: imageMessage, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp(""), ExpectedURN: "wechat:1234", ExpectedExternalID: "123456", ExpectedAttachments: []string{"https://api.weixin.qq.com/cgi-bin/media/get?media_id=12"}, ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, - {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedStatus: 200, ExpectedResponse: "Event Accepted", - ExpectedChannelEvent: courier.NewConversation, ExpectedURN: "wechat:1234"}, + {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedRespStatus: 200, ExpectedRespBody: "Event Accepted", + ExpectedEvent: courier.NewConversation, ExpectedURN: "wechat:1234"}, - {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, ExpectedStatus: 200, ExpectedResponse: "unknown event"}, + {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, ExpectedRespStatus: 200, ExpectedRespBody: "unknown event"}, - {Label: "Verify URL", URL: receiveURL, ExpectedStatus: 200, ExpectedResponse: "SUCCESS", + {Label: "Verify URL", URL: receiveURL, ExpectedRespStatus: 200, ExpectedRespBody: "SUCCESS", PrepRequest: addValidSignature}, - {Label: "Verify URL Invalid signature", URL: receiveURL, ExpectedStatus: 400, ExpectedResponse: "unknown request", + {Label: "Verify URL Invalid signature", URL: receiveURL, ExpectedRespStatus: 400, ExpectedRespBody: "unknown request", PrepRequest: addInvalidSignature}, } @@ -191,12 +191,12 @@ func TestFetchAccessToken(t *testing.T) { fetchTimeout = time.Millisecond RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ - {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedStatus: 200, ExpectedResponse: ""}, + {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedRespBody: ""}, - {Label: "Verify URL", URL: receiveURL, ExpectedStatus: 200, ExpectedResponse: "SUCCESS", + {Label: "Verify URL", URL: receiveURL, ExpectedRespStatus: 200, ExpectedRespBody: "SUCCESS", PrepRequest: addValidSignature}, - {Label: "Verify URL Invalid signature", URL: receiveURL, ExpectedStatus: 400, ExpectedResponse: "unknown request", + {Label: "Verify URL Invalid signature", URL: receiveURL, ExpectedRespStatus: 400, ExpectedRespBody: "unknown request", PrepRequest: addInvalidSignature}, }) @@ -329,7 +329,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Accept": "application/json", }, ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"Simple Message ☺"}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", SendPrep: setSendURL, }, @@ -343,7 +343,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Accept": "application/json", }, ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"I need to keep adding more things to make it work"}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", SendPrep: setSendURL, }, @@ -358,7 +358,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Accept": "application/json", }, ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"My pic!\nhttps://foo.bar/image.jpg"}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", SendPrep: setSendURL, }, @@ -367,7 +367,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "Error Message", MsgURN: "wechat:12345", MockResponseStatus: 401, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index 53b135104..1c0ba87ec 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -292,37 +292,37 @@ var ( ) var waTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: waReceiveURL, Data: helloMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + {Label: "Receive Valid Message", URL: waReceiveURL, Data: helloMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, ExpectedContactName: Sp("Jerry Cooney"), ExpectedMsgText: Sp("hello world"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Duplicate Valid Message", URL: waReceiveURL, Data: duplicateMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + {Label: "Receive Duplicate Valid Message", URL: waReceiveURL, Data: duplicateMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, ExpectedMsgText: Sp("hello world"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Audio Message", URL: waReceiveURL, Data: audioMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + {Label: "Receive Valid Audio Message", URL: waReceiveURL, Data: audioMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Button Message", URL: waReceiveURL, Data: buttonMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + {Label: "Receive Valid Button Message", URL: waReceiveURL, Data: buttonMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, ExpectedMsgText: Sp("BUTTON1"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Document Message", URL: waReceiveURL, Data: documentMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + {Label: "Receive Valid Document Message", URL: waReceiveURL, Data: documentMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, ExpectedMsgText: Sp("the caption"), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Image Message", URL: waReceiveURL, Data: imageMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + {Label: "Receive Valid Image Message", URL: waReceiveURL, Data: imageMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, ExpectedMsgText: Sp("the caption"), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Interactive Button Message", URL: waReceiveURL, Data: interactiveButtonMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + {Label: "Receive Valid Interactive Button Message", URL: waReceiveURL, Data: interactiveButtonMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, ExpectedMsgText: Sp("BUTTON1"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Interactive List Message", URL: waReceiveURL, Data: interactiveListMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + {Label: "Receive Valid Interactive List Message", URL: waReceiveURL, Data: interactiveListMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, ExpectedMsgText: Sp("ROW1"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Location Message", URL: waReceiveURL, Data: locationMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + {Label: "Receive Valid Location Message", URL: waReceiveURL, Data: locationMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Video Message", URL: waReceiveURL, Data: videoMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + {Label: "Receive Valid Video Message", URL: waReceiveURL, Data: videoMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Voice Message", URL: waReceiveURL, Data: voiceMsg, ExpectedStatus: 200, ExpectedResponse: `"type":"msg"`, + {Label: "Receive Valid Voice Message", URL: waReceiveURL, Data: voiceMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: invalidMsg, ExpectedStatus: 400, ExpectedResponse: "unable to parse"}, - {Label: "Receive Invalid From", URL: waReceiveURL, Data: invalidFrom, ExpectedStatus: 400, ExpectedResponse: "invalid whatsapp id"}, - {Label: "Receive Invalid Timestamp", URL: waReceiveURL, Data: invalidTimestamp, ExpectedStatus: 400, ExpectedResponse: "invalid timestamp"}, + {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: invalidMsg, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse"}, + {Label: "Receive Invalid From", URL: waReceiveURL, Data: invalidFrom, ExpectedRespStatus: 400, ExpectedRespBody: "invalid whatsapp id"}, + {Label: "Receive Invalid Timestamp", URL: waReceiveURL, Data: invalidTimestamp, ExpectedRespStatus: 400, ExpectedRespBody: "invalid timestamp"}, - {Label: "Receive Valid Status", URL: waReceiveURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `"type":"status"`, + {Label: "Receive Valid Status", URL: waReceiveURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"status"`, ExpectedMsgStatus: "S", ExpectedExternalID: "9712A34B4A8B6AD50F"}, - {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: "not json", ExpectedStatus: 400, ExpectedResponse: "unable to parse"}, - {Label: "Receive Invalid Status", URL: waReceiveURL, Data: invalidStatus, ExpectedStatus: 400, ExpectedResponse: `"unknown status: in_orbit"`}, - {Label: "Receive Ignore Status", URL: waReceiveURL, Data: ignoreStatus, ExpectedStatus: 200, ExpectedResponse: `"ignoring status: deleted"`}, + {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: "not json", ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse"}, + {Label: "Receive Invalid Status", URL: waReceiveURL, Data: invalidStatus, ExpectedRespStatus: 400, ExpectedRespBody: `"unknown status: in_orbit"`}, + {Label: "Receive Ignore Status", URL: waReceiveURL, Data: ignoreStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"ignoring status: deleted"`}, } func TestBuildMediaRequest(t *testing.T) { @@ -380,7 +380,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 201, ExpectedRequestBody: `{"to":"250788123123","type":"text","preview_url":true,"text":{"body":"Link Sending https://link.com"}}`, ExpectedRequestPath: "/v1/messages", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -392,7 +392,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 201, ExpectedRequestBody: `{"to":"250788123123","type":"text","text":{"body":"Simple Message"}}`, ExpectedRequestPath: "/v1/messages", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -403,7 +403,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, MockResponseStatus: 201, ExpectedRequestBody: `{"to":"250788123123","type":"text","text":{"body":"☺"}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -414,7 +414,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "errors": [{ "title": "Error Sending" }] }`, MockResponseStatus: 403, ExpectedRequestBody: `{"to":"250788123123","type":"text","text":{"body":"Error"}}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -424,7 +424,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "errors": [{ "title": "Too many requests" }] }`, MockResponseStatus: 429, ExpectedRequestBody: `{"to":"250788123123","type":"text","text":{"body":"Error"}}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -434,7 +434,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "messages": [] }`, MockResponseStatus: 200, ExpectedRequestBody: `{"to":"250788123123","type":"text","text":{"body":"Error"}}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -444,7 +444,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "errors": [{"title":"Error Sending"}] }`, MockResponseStatus: 200, ExpectedRequestBody: `{"to":"250788123123","type":"text","text":{"body":"Error"}}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, { @@ -464,7 +464,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Body: `{"to":"250788123123","type":"text","text":{"body":"audio has no caption, sent as text"}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -485,7 +485,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Body: `{"to":"250788123123","type":"text","preview_url":true,"text":{"body":"audio has no caption, sent as text with a https://example.com"}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -501,7 +501,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Body: `{"to":"250788123123","type":"document","document":{"link":"https://foo.bar/document.pdf","caption":"document caption","filename":"document.pdf"}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -517,7 +517,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Body: `{"to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg","caption":"document caption"}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -533,7 +533,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Body: `{"to":"250788123123","type":"video","video":{"link":"https://foo.bar/video.mp4","caption":"video caption"}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -545,7 +545,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, MockResponseStatus: 200, ExpectedRequestBody: `{"to":"250788123123","type":"template","template":{"namespace":"waba_namespace","name":"revive_issue","language":{"policy":"deterministic","code":"en"},"components":[{"type":"body","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -557,7 +557,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, MockResponseStatus: 200, ExpectedRequestBody: `{"to":"250788123123","type":"template","template":{"namespace":"waba_namespace","name":"revive_issue","language":{"policy":"deterministic","code":"en_US"},"components":[{"type":"body","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -569,7 +569,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, MockResponseStatus: 200, ExpectedRequestBody: `{"to":"250788123123","type":"template","template":{"namespace":"wa_template_namespace","name":"revive_issue","language":{"policy":"deterministic","code":"en_US"},"components":[{"type":"body","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -596,8 +596,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ Body: `{"blocking":"wait","contacts":["+250788123123"],"force_check":true}`, }: httpx.NewMockResponse(200, nil, []byte(`{"contacts":[{"input":"+250788123123","status":"invalid"}]}`)), }, - ExpectedStatus: "E", - SendPrep: setSendURL, + ExpectedMsgStatus: "E", + SendPrep: setSendURL, }, { Label: "Try Messaging Again After WhatsApp Contact Check", @@ -621,7 +621,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Body: `{"to":"250788123123","type":"text","text":{"body":"try again"}}`, }: httpx.NewMockResponse(201, nil, []byte(`{"messages": [{"id": "157b5e14568e8"}]}`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -647,7 +647,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Body: `{"to":"250788123123","type":"text","text":{"body":"try again"}}`, }: httpx.NewMockResponse(201, nil, []byte(`{"messages": [{"id": "157b5e14568e8"}]}`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -673,7 +673,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Body: `{"to":"558299887766","type":"text","text":{"body":"try again"}}`, }: httpx.NewMockResponse(201, nil, []byte(`{"messages": [{"id": "157b5e14568e8"}]}`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -685,7 +685,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, MockResponseStatus: 201, ExpectedRequestBody: `{"to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL}, { @@ -696,7 +696,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, MockResponseStatus: 201, ExpectedRequestBody: `{"to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL}, { @@ -717,7 +717,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Body: `{"to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -739,7 +739,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Body: `{"to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -751,7 +751,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 201, ExpectedRequestBody: `{"to":"5511987654321","type":"text","text":{"body":"Simple Message"}}`, ExpectedRequestPath: "/v1/messages", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", ExpectedNewURN: "whatsapp:551187654321", SendPrep: setSendURL, @@ -776,7 +776,7 @@ var mediaCacheSendTestCases = []ChannelSendTestCase{ BodyContains: `/document.pdf`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -792,7 +792,7 @@ var mediaCacheSendTestCases = []ChannelSendTestCase{ BodyContains: `/document.pdf`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -813,7 +813,7 @@ var mediaCacheSendTestCases = []ChannelSendTestCase{ Body: `{"to":"250788123123","type":"video","video":{"id":"36c484d1-1283-4b94-988d-7276bdec4de2","caption":"video caption"}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -829,7 +829,7 @@ var mediaCacheSendTestCases = []ChannelSendTestCase{ Body: `{"to":"250788123123","type":"video","video":{"id":"36c484d1-1283-4b94-988d-7276bdec4de2","caption":"video caption"}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -850,7 +850,7 @@ var mediaCacheSendTestCases = []ChannelSendTestCase{ Body: `{"to":"250788123123","type":"document","document":{"id":"25c484d1-1283-4b94-988d-7276bdec4ef3","caption":"document caption","filename":"document2.pdf"}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -866,7 +866,7 @@ var mediaCacheSendTestCases = []ChannelSendTestCase{ Body: `{"to":"250788123123","type":"document","document":{"id":"25c484d1-1283-4b94-988d-7276bdec4ef3","caption":"document caption","filename":"document2.pdf"}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, @@ -881,7 +881,7 @@ var hsmSupportSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, MockResponseStatus: 200, ExpectedRequestBody: `{"to":"250788123123","type":"hsm","hsm":{"namespace":"waba_namespace","element_name":"revive_issue","language":{"policy":"deterministic","code":"en"},"localizable_params":[{"default":"Chef"},{"default":"tomorrow"}]}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, diff --git a/handlers/yo/yo_test.go b/handlers/yo/yo_test.go index f91299712..ed27d7d71 100644 --- a/handlers/yo/yo_test.go +++ b/handlers/yo/yo_test.go @@ -26,18 +26,18 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, - {Label: "Receive Valid From", URL: receiveValidMessageFrom, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid From", URL: receiveValidMessageFrom, Data: "", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, - {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC)}, - {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "", ExpectedStatus: 200, ExpectedResponse: "Accepted", + {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC)}, - {Label: "Invalid URN", URL: receiveInvalidURN, Data: "", ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from'"}, - {Label: "Receive No Sender", URL: receiveNoSender, Data: "", ExpectedStatus: 400, ExpectedResponse: "must have one of 'sender' or 'from'"}, - {Label: "Receive Invalid Date", URL: receiveInvalidDate, Data: "", ExpectedStatus: 400, ExpectedResponse: "invalid date format, must be RFC 3339"}, + {Label: "Invalid URN", URL: receiveInvalidURN, Data: "", ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, + {Label: "Receive No Params", URL: receiveNoParams, Data: "", ExpectedRespStatus: 400, ExpectedRespBody: "must have one of 'sender' or 'from'"}, + {Label: "Receive No Sender", URL: receiveNoSender, Data: "", ExpectedRespStatus: 400, ExpectedRespBody: "must have one of 'sender' or 'from'"}, + {Label: "Receive Invalid Date", URL: receiveInvalidDate, Data: "", ExpectedRespStatus: 400, ExpectedRespBody: "invalid date format, must be RFC 3339"}, } func TestHandler(t *testing.T) { @@ -56,8 +56,8 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var getSendTestCases = []ChannelSendTestCase{ {Label: "Plain Send", MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "ybs_autocreate_status=OK", MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: "ybs_autocreate_status=OK", MockResponseStatus: 200, ExpectedURLParams: map[string]string{ "sms_content": "Simple Message", "destinations": "250788383383", @@ -67,33 +67,33 @@ var getSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL}, {Label: "Blacklisted", MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "F", - MockResponseBody: "ybs_autocreate_status=ERROR&ybs_autocreate_message=256794224665%3ABLACKLISTED", MockResponseStatus: 200, + ExpectedMsgStatus: "F", + MockResponseBody: "ybs_autocreate_status=ERROR&ybs_autocreate_message=256794224665%3ABLACKLISTED", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"sms_content": "Simple Message", "destinations": string("250788383383"), "origin": "2020"}, SendPrep: setSendURL, ExpectedStopEvent: true}, {Label: "Errored wrong authorization", MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: "ybs_autocreate_status=ERROR&ybs_autocreate_message=YBS+AutoCreate+Subsystem%3A+Access+denied+due+to+wrong+authorization+code", MockResponseStatus: 200, + ExpectedMsgStatus: "E", + MockResponseBody: "ybs_autocreate_status=ERROR&ybs_autocreate_message=YBS+AutoCreate+Subsystem%3A+Access+denied+due+to+wrong+authorization+code", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"sms_content": "Simple Message", "destinations": string("250788383383"), "origin": "2020"}, SendPrep: setSendURL}, {Label: "Unicode Send", MsgText: "☺", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", - MockResponseBody: "ybs_autocreate_status=OK", MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: "ybs_autocreate_status=OK", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"sms_content": "☺", "destinations": string("250788383383"), "origin": "2020"}, SendPrep: setSendURL}, {Label: "Error Sending", MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedStatus: "E", - MockResponseBody: "Error", MockResponseStatus: 401, + ExpectedMsgStatus: "E", + MockResponseBody: "Error", MockResponseStatus: 401, ExpectedURLParams: map[string]string{"sms_content": `Error Message`, "destinations": string("250788383383")}, SendPrep: setSendURL}, {Label: "Send Attachment", MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedStatus: "W", - MockResponseBody: "ybs_autocreate_status=OK", MockResponseStatus: 200, + ExpectedMsgStatus: "W", + MockResponseBody: "ybs_autocreate_status=OK", MockResponseStatus: 200, ExpectedURLParams: map[string]string{"sms_content": "My pic!\nhttps://foo.bar/image.jpg", "destinations": string("250788383383"), "origin": "2020"}, SendPrep: setSendURL}, } diff --git a/handlers/zenvia/zenvia_test.go b/handlers/zenvia/zenvia_test.go index ef32b3ddb..a052d7f5d 100644 --- a/handlers/zenvia/zenvia_test.go +++ b/handlers/zenvia/zenvia_test.go @@ -196,45 +196,45 @@ var missingFieldsReceive = `{ }` var testWhatappCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveWhatsappURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + {Label: "Receive Valid", URL: receiveWhatsappURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", ExpectedMsgText: Sp("Msg"), ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, - {Label: "Receive file Valid", URL: receiveWhatsappURL, Data: fileReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + {Label: "Receive file Valid", URL: receiveWhatsappURL, Data: fileReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, - {Label: "Receive location Valid", URL: receiveWhatsappURL, Data: locationReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + {Label: "Receive location Valid", URL: receiveWhatsappURL, Data: locationReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, - {Label: "Not JSON body", URL: receiveWhatsappURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: receiveWhatsappURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, - {Label: "Missing field", URL: receiveWhatsappURL, Data: missingFieldsReceive, ExpectedStatus: 400, ExpectedResponse: "validation for 'ID' failed on the 'required'"}, - {Label: "Bad Date", URL: receiveWhatsappURL, Data: invalidDateReceive, ExpectedStatus: 400, ExpectedResponse: "invalid date format"}, + {Label: "Not JSON body", URL: receiveWhatsappURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: receiveWhatsappURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedRespBody: "request JSON doesn't match required schema"}, + {Label: "Missing field", URL: receiveWhatsappURL, Data: missingFieldsReceive, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'ID' failed on the 'required'"}, + {Label: "Bad Date", URL: receiveWhatsappURL, Data: invalidDateReceive, ExpectedRespStatus: 400, ExpectedRespBody: "invalid date format"}, - {Label: "Valid Status", URL: statusWhatsppURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `Accepted`, ExpectedMsgStatus: "S"}, - {Label: "Unkown Status", URL: statusWhatsppURL, Data: unknownStatus, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgStatus: "E"}, - {Label: "Not JSON body", URL: statusWhatsppURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: statusWhatsppURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, + {Label: "Valid Status", URL: statusWhatsppURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `Accepted`, ExpectedMsgStatus: "S"}, + {Label: "Unkown Status", URL: statusWhatsppURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgStatus: "E"}, + {Label: "Not JSON body", URL: statusWhatsppURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: statusWhatsppURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedRespBody: "request JSON doesn't match required schema"}, } var testSMSCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveSMSURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + {Label: "Receive Valid", URL: receiveSMSURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", ExpectedMsgText: Sp("Msg"), ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, - {Label: "Receive file Valid", URL: receiveSMSURL, Data: fileReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + {Label: "Receive file Valid", URL: receiveSMSURL, Data: fileReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, - {Label: "Receive location Valid", URL: receiveSMSURL, Data: locationReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + {Label: "Receive location Valid", URL: receiveSMSURL, Data: locationReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, - {Label: "Not JSON body", URL: receiveSMSURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: receiveSMSURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, - {Label: "Missing field", URL: receiveSMSURL, Data: missingFieldsReceive, ExpectedStatus: 400, ExpectedResponse: "validation for 'ID' failed on the 'required'"}, - {Label: "Bad Date", URL: receiveSMSURL, Data: invalidDateReceive, ExpectedStatus: 400, ExpectedResponse: "invalid date format"}, + {Label: "Not JSON body", URL: receiveSMSURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: receiveSMSURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedRespBody: "request JSON doesn't match required schema"}, + {Label: "Missing field", URL: receiveSMSURL, Data: missingFieldsReceive, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'ID' failed on the 'required'"}, + {Label: "Bad Date", URL: receiveSMSURL, Data: invalidDateReceive, ExpectedRespStatus: 400, ExpectedRespBody: "invalid date format"}, - {Label: "Valid Status", URL: statusSMSURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `Accepted`, ExpectedMsgStatus: "S"}, - {Label: "Unkown Status", URL: statusSMSURL, Data: unknownStatus, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgStatus: "E"}, - {Label: "Not JSON body", URL: statusSMSURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: statusSMSURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, + {Label: "Valid Status", URL: statusSMSURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `Accepted`, ExpectedMsgStatus: "S"}, + {Label: "Unkown Status", URL: statusSMSURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgStatus: "E"}, + {Label: "Not JSON body", URL: statusSMSURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: statusSMSURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedRespBody: "request JSON doesn't match required schema"}, } func TestHandler(t *testing.T) { @@ -266,7 +266,7 @@ var defaultWhatsappSendTestCases = []ChannelSendTestCase{ "X-API-TOKEN": "zv-api-token", }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"Simple Message ☺"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "55555", SendPrep: setSendURL, }, @@ -282,7 +282,7 @@ var defaultWhatsappSendTestCases = []ChannelSendTestCase{ "X-API-TOKEN": "zv-api-token", }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say,"},{"type":"text","text":"I need to keep adding more things to make it work"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "55555", SendPrep: setSendURL, }, @@ -299,7 +299,7 @@ var defaultWhatsappSendTestCases = []ChannelSendTestCase{ "X-API-TOKEN": "zv-api-token", }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"file","fileUrl":"https://foo.bar/image.jpg","fileMimeType":"image/jpeg"},{"type":"text","text":"My pic!"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "55555", SendPrep: setSendURL, }, @@ -315,7 +315,7 @@ var defaultWhatsappSendTestCases = []ChannelSendTestCase{ "X-API-TOKEN": "zv-api-token", }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"No External ID"}]}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get id from body", "")}, SendPrep: setSendURL, }, @@ -326,7 +326,7 @@ var defaultWhatsappSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"Error Message"}]}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } @@ -344,7 +344,7 @@ var defaultSMSSendTestCases = []ChannelSendTestCase{ "X-API-TOKEN": "zv-api-token", }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"Simple Message ☺"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "55555", SendPrep: setSendURL}, { @@ -359,7 +359,7 @@ var defaultSMSSendTestCases = []ChannelSendTestCase{ "X-API-TOKEN": "zv-api-token", }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say,"},{"type":"text","text":"I need to keep adding more things to make it work"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "55555", SendPrep: setSendURL}, { @@ -375,7 +375,7 @@ var defaultSMSSendTestCases = []ChannelSendTestCase{ "X-API-TOKEN": "zv-api-token", }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"My pic!\nhttps://foo.bar/image.jpg"}]}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "55555", SendPrep: setSendURL, }, @@ -391,7 +391,7 @@ var defaultSMSSendTestCases = []ChannelSendTestCase{ "X-API-TOKEN": "zv-api-token", }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"No External ID"}]}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get id from body", "")}, SendPrep: setSendURL, }, @@ -402,7 +402,7 @@ var defaultSMSSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"Error Message"}]}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } diff --git a/handlers/zenviaold/zenviaold_test.go b/handlers/zenviaold/zenviaold_test.go index 1f7f46ff0..1a0087299 100644 --- a/handlers/zenviaold/zenviaold_test.go +++ b/handlers/zenviaold/zenviaold_test.go @@ -105,21 +105,21 @@ var missingFieldsReceive = `{ }` var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedStatus: 200, ExpectedResponse: "Message Accepted", + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+254791541111", ExpectedDate: time.Date(2017, 5, 3, 06, 04, 45, 123000000, time.UTC)}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedStatus: 400, ExpectedResponse: "phone number supplied is not a number"}, - {Label: "Not JSON body", URL: receiveURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: receiveURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, - {Label: "Missing field", URL: receiveURL, Data: missingFieldsReceive, ExpectedStatus: 400, ExpectedResponse: "validation for 'ID' failed on the 'required'"}, - {Label: "Bad Date", URL: receiveURL, Data: invalidDateReceive, ExpectedStatus: 400, ExpectedResponse: "invalid date format"}, - - {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedStatus: 200, ExpectedResponse: `Accepted`, ExpectedMsgStatus: "D"}, - {Label: "Valid Status with more fields", URL: statusURL, Data: validWithMoreFieldsStatus, ExpectedStatus: 200, ExpectedResponse: `Accepted`, ExpectedMsgStatus: "D"}, - {Label: "Unkown Status", URL: statusURL, Data: unknownStatus, ExpectedStatus: 200, ExpectedResponse: "Accepted", ExpectedMsgStatus: "E"}, - {Label: "Not JSON body", URL: statusURL, Data: notJSON, ExpectedStatus: 400, ExpectedResponse: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: statusURL, Data: wrongJSONSchema, ExpectedStatus: 400, ExpectedResponse: "request JSON doesn't match required schema"}, - {Label: "Missing field", URL: statusURL, Data: missingFieldsStatus, ExpectedStatus: 400, ExpectedResponse: "validation for 'StatusCode' failed on the 'required'"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, + {Label: "Not JSON body", URL: receiveURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: receiveURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedRespBody: "request JSON doesn't match required schema"}, + {Label: "Missing field", URL: receiveURL, Data: missingFieldsReceive, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'ID' failed on the 'required'"}, + {Label: "Bad Date", URL: receiveURL, Data: invalidDateReceive, ExpectedRespStatus: 400, ExpectedRespBody: "invalid date format"}, + + {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `Accepted`, ExpectedMsgStatus: "D"}, + {Label: "Valid Status with more fields", URL: statusURL, Data: validWithMoreFieldsStatus, ExpectedRespStatus: 200, ExpectedRespBody: `Accepted`, ExpectedMsgStatus: "D"}, + {Label: "Unkown Status", URL: statusURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgStatus: "E"}, + {Label: "Not JSON body", URL: statusURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: statusURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedRespBody: "request JSON doesn't match required schema"}, + {Label: "Missing field", URL: statusURL, Data: missingFieldsStatus, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'StatusCode' failed on the 'required'"}, } func TestHandler(t *testing.T) { @@ -148,7 +148,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", }, ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"Simple Message ☺","callbackOption":"FINAL","id":"10","aggregateId":""}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", SendPrep: setSendURL, }, @@ -156,7 +156,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Label: "Long Send", MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", MsgURN: "tel:+250788383383", - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", MockResponseBody: `{"sendSmsResponse":{"statusCode":"00","statusDescription":"Ok","detailCode":"000","detailDescription":"Message Sent"}}`, MockResponseStatus: 200, @@ -181,7 +181,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", }, ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"My pic!\nhttps://foo.bar/image.jpg","callbackOption":"FINAL","id":"10","aggregateId":""}}`, - ExpectedStatus: "W", + ExpectedMsgStatus: "W", ExpectedExternalID: "", SendPrep: setSendURL, }, @@ -197,7 +197,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", }, ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"No External ID","callbackOption":"FINAL","id":"10","aggregateId":""}}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received non-success response: '05'", "")}, SendPrep: setSendURL}, { @@ -207,7 +207,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 401, ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"Error Message","callbackOption":"FINAL","id":"10","aggregateId":""}}`, - ExpectedStatus: "E", + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } From 778247417ca51f4b817f75e23c53f47a68ceebf9 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 29 Aug 2022 14:32:42 -0500 Subject: [PATCH 121/294] Simplify handlers.Sp --- handlers/test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/handlers/test.go b/handlers/test.go index 57e810791..b640e462c 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "fmt" "io" "mime/multipart" "net/http" @@ -12,8 +13,6 @@ import ( "testing" "time" - "fmt" - _ "github.com/lib/pq" // postgres driver "github.com/nyaruka/courier" "github.com/nyaruka/courier/test" @@ -104,7 +103,7 @@ type ChannelSendTestCase struct { } // Sp is a utility method to get the pointer to the passed in string -func Sp(str interface{}) *string { asStr := fmt.Sprintf("%s", str); return &asStr } +func Sp(s string) *string { return &s } // utility method to make a request to a handler URL func testHandlerRequest(tb testing.TB, s courier.Server, path string, headers map[string]string, data string, multipartFormFields map[string]string, expectedStatus int, expectedBody *string, requestPrepFunc RequestPrepFunc) string { From 71ba680d42e5183c0093fe8e4eead59a7a2b1935 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 29 Aug 2022 15:31:51 -0500 Subject: [PATCH 122/294] Format more test cases --- .../highconnection/highconnection_test.go | 68 ++++-- handlers/hormuud/hormuud_test.go | 106 ++++++--- handlers/infobip/infobip_test.go | 110 +++++++-- handlers/jasmin/jasmin_test.go | 176 +++++++++----- handlers/start/start_test.go | 143 +++++++++--- handlers/telegram/telegram_test.go | 216 ++++++++++++++---- handlers/telesom/telesom_test.go | 147 ++++++++---- 7 files changed, 723 insertions(+), 243 deletions(-) diff --git a/handlers/highconnection/highconnection_test.go b/handlers/highconnection/highconnection_test.go index 6d2b374db..fb96e5c00 100644 --- a/handlers/highconnection/highconnection_test.go +++ b/handlers/highconnection/highconnection_test.go @@ -14,33 +14,65 @@ var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "HX", "2020", "US", nil), } -var ( +const ( receiveURL = "/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" statusURL = "/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/" - - validReceive = "FROM=+33610346460&TO=5151&MESSAGE=Hello+World&RECEPTION_DATE=2015-04-02T14%3A26%3A06" - validAccentReceive = "FROM=+33610346460&TO=5151&MESSAGE=je+suis+tr%E8s+satisfait+&RECEPTION_DATE=2015-04-02T14%3A26%3A06" - invalidURN = "FROM=MTN&TO=5151&MESSAGE=Hello+World&RECEPTION_DATE=2015-04-02T14%3A26%3A06" - invalidDateReceive = "FROM=+33610346460&TO=5151&MESSAGE=Hello+World&RECEPTION_DATE=2015-04-02T14:26" - validStatus = statusURL + "?ret_id=12345&status=6" ) var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Hello World"), ExpectedURN: "tel:+33610346460", - ExpectedDate: time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC), + Label: "Receive Valid Message", + URL: receiveURL, + Data: "FROM=+33610346460&TO=5151&MESSAGE=Hello+World&RECEPTION_DATE=2015-04-02T14%3A26%3A06", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: "tel:+33610346460", + ExpectedDate: time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC), + }, + { + Label: "Receive Valid Message with accents", + URL: receiveURL, + Data: "FROM=+33610346460&TO=5151&MESSAGE=je+suis+tr%E8s+satisfait+&RECEPTION_DATE=2015-04-02T14%3A26%3A06", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("je suis très satisfait "), + ExpectedURN: "tel:+33610346460", + ExpectedDate: time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC), + }, + { + Label: "Invalid URN", + URL: receiveURL, + Data: "FROM=MTN&TO=5151&MESSAGE=Hello+World&RECEPTION_DATE=2015-04-02T14%3A26%3A06", + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", + }, + { + Label: "Receive Missing Params", + URL: receiveURL, + Data: " ", + ExpectedRespStatus: 400, + ExpectedRespBody: "validation for 'From' failed", + }, + { + Label: "Receive Invalid Date", + URL: receiveURL, + Data: "FROM=+33610346460&TO=5151&MESSAGE=Hello+World&RECEPTION_DATE=2015-04-02T14:26", + ExpectedRespStatus: 400, + ExpectedRespBody: "cannot parse", + }, + { + Label: "Status Missing Params", + URL: statusURL, + ExpectedRespStatus: 400, + ExpectedRespBody: "validation for 'Status' failed", }, { - Label: "Receive Valid Message with accents", URL: receiveURL, Data: validAccentReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("je suis très satisfait "), ExpectedURN: "tel:+33610346460", - ExpectedDate: time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC), + Label: "Status Delivered", + URL: statusURL + "?ret_id=12345&status=6", + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"D"`, }, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, - {Label: "Receive Missing Params", URL: receiveURL, Data: " ", ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'From' failed"}, - {Label: "Receive Invalid Date", URL: receiveURL, Data: invalidDateReceive, ExpectedRespStatus: 400, ExpectedRespBody: "cannot parse"}, - {Label: "Status Missing Params", URL: statusURL, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'Status' failed"}, - {Label: "Status Delivered", URL: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`}, } func TestHandler(t *testing.T) { diff --git a/handlers/hormuud/hormuud_test.go b/handlers/hormuud/hormuud_test.go index 561c8eb2e..6ff3b34fa 100644 --- a/handlers/hormuud/hormuud_test.go +++ b/handlers/hormuud/hormuud_test.go @@ -16,9 +16,9 @@ var ( receiveValidMessage = "/c/hm/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?Sender=%2B2349067554729&MessageText=Join&TimeSent=1493735509&&ShortCode=2020" receiveInvalidURN = "/c/hm/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?Sender=bad&MessageText=Join&TimeSent=1493735509&&ShortCode=2020" receiveEmptyMessage = "/c/hm/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?Sender=%2B2349067554729&MessageText=&TimeSent=1493735509&&ShortCode=2020" - statusNoParams = "/c/hm/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/" - statusInvalidStatus = "/c/hm/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/?id=12345&status=66" - statusValid = "/c/hm/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/?id=12345&status=4" + //statusNoParams = "/c/hm/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/" + //statusInvalidStatus = "/c/hm/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/?id=12345&status=66" + //statusValid = "/c/hm/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/?id=12345&status=4" ) var testChannels = []courier.Channel{ @@ -26,12 +26,40 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp(""), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "field 'sender' required"}, - {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, + { + Label: "Receive Valid Message", + URL: receiveValidMessage, + Data: "empty", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC), + }, + { + Label: "Receive Empty Message", + URL: receiveEmptyMessage, + Data: "empty", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedURN: "tel:+2349067554729", + ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC), + }, + { + Label: "Receive No Params", + URL: receiveNoParams, + Data: "empty", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'sender' required", + }, + { + Label: "Invalid URN", + URL: receiveInvalidURN, + Data: "empty", + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", + }, // {Label: "Status No Params", URL: statusNoParams, Status: 400, Response: "field 'status' required"}, // {Label: "Status Invalid Status", URL: statusInvalidStatus, Status: 400, Response: "unknown status '66', must be one of 1,2,4,8,16"}, // {Label: "Status Valid", URL: statusValid, Status: 200, Response: `"status":"S"`}, @@ -47,29 +75,49 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var sendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedMsgStatus: "W", ExpectedExternalID: "msg1", - MockResponseBody: `{"ResCode": "res", "ResMsg": "msg", "Data": { "MessageID": "msg1", "Description": "accepted" } }`, MockResponseStatus: 200, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"ResCode": "res", "ResMsg": "msg", "Data": { "MessageID": "msg1", "Description": "accepted" } }`, + MockResponseStatus: 200, ExpectedRequestBody: `{"mobile":"250788383383","message":"Simple Message","senderid":"2020","mType":-1,"eType":-1,"UDH":""}`, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: "☺", MsgURN: "tel:+250788383383", - ExpectedMsgStatus: "W", ExpectedExternalID: "msg1", - MockResponseBody: `{"ResCode": "res", "ResMsg": "msg", "Data": { "MessageID": "msg1", "Description": "accepted" } }`, MockResponseStatus: 200, + ExpectedMsgStatus: "W", + ExpectedExternalID: "msg1", + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"ResCode": "res", "ResMsg": "msg", "Data": { "MessageID": "msg1", "Description": "accepted" } }`, + MockResponseStatus: 200, ExpectedRequestBody: `{"mobile":"250788383383","message":"☺","senderid":"2020","mType":-1,"eType":-1,"UDH":""}`, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedMsgStatus: "W", ExpectedExternalID: "msg1", - MockResponseBody: `{"ResCode": "res", "ResMsg": "msg", "Data": { "MessageID": "msg1", "Description": "accepted" } }`, MockResponseStatus: 200, + ExpectedMsgStatus: "W", + ExpectedExternalID: "msg1", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{"ResCode": "res", "ResMsg": "msg", "Data": { "MessageID": "msg1", "Description": "accepted" } }`, + MockResponseStatus: 200, ExpectedRequestBody: `{"mobile":"250788383383","message":"My pic!\nhttps://foo.bar/image.jpg","senderid":"2020","mType":-1,"eType":-1,"UDH":""}`, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Sending", MsgURN: "tel:+250788383383", - ExpectedMsgStatus: "E", - MockResponseBody: `[{"Response": "101"}]`, MockResponseStatus: 403, - SendPrep: setSendURL}, + ExpectedMsgStatus: "W", + ExpectedExternalID: "msg1", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Sending", + MsgURN: "tel:+250788383383", + MockResponseBody: `[{"Response": "101"}]`, + MockResponseStatus: 403, + ExpectedMsgStatus: "E", + SendPrep: setSendURL, + }, } var tokenTestCases = []ChannelSendTestCase{ diff --git a/handlers/infobip/infobip_test.go b/handlers/infobip/infobip_test.go index c3f5bd674..309226ca6 100644 --- a/handlers/infobip/infobip_test.go +++ b/handlers/infobip/infobip_test.go @@ -14,8 +14,10 @@ var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "IB", "2020", "US", nil), } -var receiveURL = "/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" -var statusURL = "/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered/" +const ( + receiveURL = "/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" + statusURL = "/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered/" +) var helloMsg = `{ "results": [ @@ -191,19 +193,93 @@ var invalidStatus = `{ }` var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: helloMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("QUIZ Correct answer is Paris"), ExpectedURN: "tel:+385916242493", ExpectedExternalID: "817790313235066447", ExpectedDate: time.Date(2016, 10, 06, 9, 28, 39, 220000000, time.FixedZone("", 0))}, - {Label: "Receive missing results key", URL: receiveURL, Data: missingResults, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'Results' failed"}, - {Label: "Receive missing text key", URL: receiveURL, Data: missingText, ExpectedRespStatus: 200, ExpectedRespBody: "ignoring request, no message"}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, - {Label: "Status report invalid JSON", URL: statusURL, Data: invalidJSONStatus, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, - {Label: "Status report missing results key", URL: statusURL, Data: statusMissingResultsKey, ExpectedRespStatus: 400, ExpectedRespBody: "Field validation for 'Results' failed"}, - {Label: "Status delivered", URL: statusURL, Data: validStatusDelivered, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`}, - {Label: "Status rejected", URL: statusURL, Data: validStatusRejected, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`}, - {Label: "Status undeliverable", URL: statusURL, Data: validStatusUndeliverable, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`}, - {Label: "Status pending", URL: statusURL, Data: validStatusPending, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`}, - {Label: "Status expired", URL: statusURL, Data: validStatusExpired, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`}, - {Label: "Status group name unexpected", URL: statusURL, Data: invalidStatus, ExpectedRespStatus: 400, ExpectedRespBody: `unknown status 'UNEXPECTED'`}, + { + Label: "Receive Valid Message", + URL: receiveURL, + Data: helloMsg, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("QUIZ Correct answer is Paris"), + ExpectedURN: "tel:+385916242493", + ExpectedExternalID: "817790313235066447", + ExpectedDate: time.Date(2016, 10, 06, 9, 28, 39, 220000000, time.FixedZone("", 0)), + }, + { + Label: "Receive missing results key", + URL: receiveURL, + Data: missingResults, + ExpectedRespStatus: 400, + ExpectedRespBody: "validation for 'Results' failed", + }, + { + Label: "Receive missing text key", + URL: receiveURL, + Data: missingText, + ExpectedRespStatus: 200, + ExpectedRespBody: "ignoring request, no message", + }, + { + Label: "Invalid URN", + URL: receiveURL, + Data: invalidURN, + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", + }, + { + Label: "Status report invalid JSON", + URL: statusURL, + Data: invalidJSONStatus, + ExpectedRespStatus: 400, + ExpectedRespBody: "unable to parse request JSON", + }, + { + Label: "Status report missing results key", + URL: statusURL, + Data: statusMissingResultsKey, + ExpectedRespStatus: 400, + ExpectedRespBody: "Field validation for 'Results' failed", + }, + { + Label: "Status delivered", + URL: statusURL, + Data: validStatusDelivered, + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"D"`, + }, + { + Label: "Status rejected", + URL: statusURL, + Data: validStatusRejected, + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"F"`, + }, + { + Label: "Status undeliverable", + URL: statusURL, + Data: validStatusUndeliverable, + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"F"`, + }, + { + Label: "Status pending", + URL: statusURL, + Data: validStatusPending, + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"S"`}, + { + Label: "Status expired", + URL: statusURL, + Data: validStatusExpired, + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"S"`, + }, + { + Label: "Status group name unexpected", + URL: statusURL, + Data: invalidStatus, + ExpectedRespStatus: 400, + ExpectedRespBody: `unknown status 'UNEXPECTED'`, + }, } func TestHandler(t *testing.T) { @@ -224,8 +300,6 @@ var defaultSendTestCases = []ChannelSendTestCase{ Label: "Plain Send", MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedMsgStatus: "W", - ExpectedExternalID: "12345", MockResponseBody: `{"messages":[{"status":{"groupId": 1}, "messageId": "12345"}}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -234,6 +308,8 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Simple Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, + ExpectedMsgStatus: "W", + ExpectedExternalID: "12345", SendPrep: setSendURL, }, { diff --git a/handlers/jasmin/jasmin_test.go b/handlers/jasmin/jasmin_test.go index 5d40d233a..20e520e86 100644 --- a/handlers/jasmin/jasmin_test.go +++ b/handlers/jasmin/jasmin_test.go @@ -10,16 +10,9 @@ import ( "github.com/nyaruka/courier/test" ) -var ( - receiveURL = "/c/js/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" - receiveValidMessage = "content=%05v%05nement&coding=0&From=2349067554729&To=2349067554711&id=1001" - receiveMissingTo = "content=%05v%05nement&coding=0&From=2349067554729&id=1001" - invalidURN = "content=%05v%05nement&coding=0&From=MTN&To=2349067554711&id=1001" - - statusURL = "/c/js/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/" - statusDelivered = "id=external1&dlvrd=1" - statusFailed = "id=external1&err=1" - statusUnknown = "id=external1&err=0&dlvrd=0" +const ( + receiveURL = "/c/js/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" + statusURL = "/c/js/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/" ) var testChannels = []courier.Channel{ @@ -27,20 +20,62 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedRespStatus: 200, ExpectedRespBody: "ACK/Jasmin", - ExpectedMsgText: Sp("événement"), ExpectedURN: "tel:+2349067554729", ExpectedExternalID: "1001"}, - {Label: "Receive Missing To", URL: receiveURL, Data: receiveMissingTo, ExpectedRespStatus: 400, - ExpectedRespBody: "field 'to' required"}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number"}, - {Label: "Status Delivered", URL: statusURL, Data: statusDelivered, ExpectedRespStatus: 200, ExpectedRespBody: "ACK/Jasmin", - ExpectedMsgStatus: "D", ExpectedExternalID: "external1"}, - {Label: "Status Failed", URL: statusURL, Data: statusFailed, ExpectedRespStatus: 200, ExpectedRespBody: "ACK/Jasmin", - ExpectedMsgStatus: "F", ExpectedExternalID: "external1"}, - {Label: "Status Missing", URL: statusURL, ExpectedRespStatus: 400, Data: "nothing", - ExpectedRespBody: "field 'id' required"}, - {Label: "Status Unknown", URL: statusURL, ExpectedRespStatus: 400, Data: statusUnknown, - ExpectedRespBody: "must have either dlvrd or err set to 1"}, + { + Label: "Receive Valid Message", + URL: receiveURL, + Data: "content=%05v%05nement&coding=0&From=2349067554729&To=2349067554711&id=1001", + ExpectedRespStatus: 200, + ExpectedRespBody: "ACK/Jasmin", + ExpectedMsgText: Sp("événement"), + ExpectedURN: "tel:+2349067554729", + ExpectedExternalID: "1001", + }, + { + Label: "Receive Missing To", + URL: receiveURL, + Data: "content=%05v%05nement&coding=0&From=2349067554729&id=1001", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'to' required", + }, + { + Label: "Invalid URN", + URL: receiveURL, + Data: "content=%05v%05nement&coding=0&From=MTN&To=2349067554711&id=1001", + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", + }, + { + Label: "Status Delivered", + URL: statusURL, + Data: "id=external1&dlvrd=1", + ExpectedRespStatus: 200, + ExpectedRespBody: "ACK/Jasmin", + ExpectedMsgStatus: "D", + ExpectedExternalID: "external1", + }, + { + Label: "Status Failed", + URL: statusURL, + Data: "id=external1&err=1", + ExpectedRespStatus: 200, + ExpectedRespBody: "ACK/Jasmin", + ExpectedMsgStatus: "F", + ExpectedExternalID: "external1", + }, + { + Label: "Status Missing", + URL: statusURL, + ExpectedRespStatus: 400, + Data: "nothing", + ExpectedRespBody: "field 'id' required", + }, + { + Label: "Status Unknown", + URL: statusURL, + ExpectedRespStatus: 400, + Data: "id=external1&err=0&dlvrd=0", + ExpectedRespBody: "must have either dlvrd or err set to 1", + }, } func TestHandler(t *testing.T) { @@ -57,38 +92,69 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", - ExpectedMsgStatus: "W", - MockResponseBody: `Success "External ID1"`, MockResponseStatus: 200, ExpectedExternalID: "External ID1", - ExpectedURLParams: map[string]string{"content": "Simple Message", "to": "250788383383", "coding": "0", - "dlr-level": "2", "dlr": "yes", "dlr-method": http.MethodPost, "username": "Username", "password": "Password", - "dlr-url": "https://localhost/c/js/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status"}, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: "☺", - ExpectedMsgStatus: "W", - MockResponseBody: `Success "External ID1"`, MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"content": "?"}, - SendPrep: setSendURL}, - {Label: "Smart Encoding", - MsgText: "Fancy “Smart” Quotes", MsgURN: "tel:+250788383383", MsgHighPriority: false, - ExpectedMsgStatus: "W", - MockResponseBody: `Success "External ID1"`, MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"content": `Fancy "Smart" Quotes`}, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgHighPriority: true, MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `Success "External ID1"`, + MockResponseStatus: 200, + ExpectedExternalID: "External ID1", + ExpectedURLParams: map[string]string{ + "content": "Simple Message", + "to": "250788383383", + "coding": "0", + "dlr-level": "2", + "dlr": "yes", + "dlr-method": http.MethodPost, + "username": "Username", + "password": "Password", + "dlr-url": "https://localhost/c/js/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status", + }, ExpectedMsgStatus: "W", - MockResponseBody: `Success "External ID1"`, MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"content": "My pic!\nhttps://foo.bar/image.jpg"}, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", MsgHighPriority: false, - ExpectedMsgStatus: "E", - MockResponseBody: "Failed Sending", MockResponseStatus: 401, - ExpectedURLParams: map[string]string{"content": `Error Message`}, - SendPrep: setSendURL}, + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "☺", + MockResponseBody: `Success "External ID1"`, + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"content": "?"}, + ExpectedMsgStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Smart Encoding", + MsgText: "Fancy “Smart” Quotes", + MsgURN: "tel:+250788383383", + MockResponseBody: `Success "External ID1"`, + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"content": `Fancy "Smart" Quotes`}, + ExpectedMsgStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgHighPriority: true, + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `Success "External ID1"`, + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"content": "My pic!\nhttps://foo.bar/image.jpg"}, + ExpectedMsgStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MsgHighPriority: false, + MockResponseBody: "Failed Sending", + MockResponseStatus: 401, + ExpectedURLParams: map[string]string{"content": `Error Message`}, + ExpectedMsgStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/start/start_test.go b/handlers/start/start_test.go index d26a8c4c9..b49be77fb 100644 --- a/handlers/start/start_test.go +++ b/handlers/start/start_test.go @@ -14,11 +14,9 @@ var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ST", "2020", "UA", map[string]interface{}{"username": "st-username", "password": "st-password"}), } -var ( +const ( receiveURL = "/c/st/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" - notXML = "empty" - validReceive = ` +250788123123 @@ -74,19 +72,79 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Hello World"), ExpectedURN: "tel:+250788123123", ExpectedDate: time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC)}, - {Label: "Receive Valid Encoded", URL: receiveURL, Data: validReceiveEncoded, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Кохання"), ExpectedURN: "tel:+380501529999", ExpectedDate: time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC)}, - {Label: "Receive Valid with empty Text", URL: receiveURL, Data: validReceiveEmptyText, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp(""), ExpectedURN: "tel:+250788123123"}, - {Label: "Receive Valid missing body", URL: receiveURL, Data: validMissingBody, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp(""), ExpectedURN: "tel:+250788123123"}, - {Label: "Receive invalidURN", URL: receiveURL, Data: invalidURNReceive, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, - {Label: "Receive missing Request ID", URL: receiveURL, Data: missingRequestID, ExpectedRespStatus: 400, ExpectedRespBody: "Error"}, - {Label: "Receive missing From", URL: receiveURL, Data: missingFrom, ExpectedRespStatus: 400, ExpectedRespBody: "Error"}, - {Label: "Receive missing To", URL: receiveURL, Data: missingTo, ExpectedRespStatus: 400, ExpectedRespBody: "Error"}, - {Label: "Invalid XML", URL: receiveURL, Data: notXML, ExpectedRespStatus: 400, ExpectedRespBody: "Error"}, + { + Label: "Receive Valid", + URL: receiveURL, + Data: validReceive, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: "tel:+250788123123", + ExpectedDate: time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC), + }, + { + Label: "Receive Valid Encoded", + URL: receiveURL, + Data: validReceiveEncoded, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Кохання"), + ExpectedURN: "tel:+380501529999", + ExpectedDate: time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC), + }, + { + Label: "Receive Valid with empty Text", + URL: receiveURL, + Data: validReceiveEmptyText, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedURN: "tel:+250788123123", + }, + { + Label: "Receive Valid missing body", + URL: receiveURL, + Data: validMissingBody, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedURN: "tel:+250788123123", + }, + { + Label: "Receive invalidURN", + URL: receiveURL, + Data: invalidURNReceive, + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", + }, + { + Label: "Receive missing Request ID", + URL: receiveURL, + Data: missingRequestID, + ExpectedRespStatus: 400, + ExpectedRespBody: "Error", + }, + { + Label: "Receive missing From", + URL: receiveURL, + Data: missingFrom, + ExpectedRespStatus: 400, + ExpectedRespBody: "Error", + }, + { + Label: "Receive missing To", + URL: receiveURL, + Data: missingTo, + ExpectedRespStatus: 400, + ExpectedRespBody: "Error", + }, + { + Label: "Invalid XML", + URL: receiveURL, + Data: "empty", + ExpectedRespStatus: 400, + ExpectedRespBody: "Error", + }, } func TestHandler(t *testing.T) { @@ -103,11 +161,10 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", + { + Label: "Plain Send", MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", - ExpectedMsgStatus: "W", - ExpectedExternalID: "380502535130309161501", MockResponseBody: `380502535130309161501Accepted`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -115,12 +172,14 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `+250788383383Simple Message ☺`, - SendPrep: setSendURL}, - {Label: "Long Send", + ExpectedMsgStatus: "W", + ExpectedExternalID: "380502535130309161501", + SendPrep: setSendURL, + }, + { + Label: "Long Send", MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", MsgURN: "tel:+250788383383", - ExpectedMsgStatus: "W", - ExpectedExternalID: "380502535130309161501", MockResponseBody: `380502535130309161501Accepted`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -128,13 +187,15 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `+250788383383I need to keep adding more things to make it work`, - SendPrep: setSendURL}, - {Label: "Send Attachment", + ExpectedMsgStatus: "W", + ExpectedExternalID: "380502535130309161501", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", MsgText: "My pic!", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MsgURN: "tel:+250788383383", - ExpectedMsgStatus: "W", - ExpectedExternalID: "380502535130309161501", MockResponseBody: `380502535130309161501Accepted`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -142,12 +203,14 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `+250788383383My pic! https://foo.bar/image.jpg`, - SendPrep: setSendURL}, - {Label: "Error Response", + ExpectedMsgStatus: "W", + ExpectedExternalID: "380502535130309161501", + SendPrep: setSendURL, + }, + { + Label: "Error Response", MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", - ExpectedMsgStatus: "E", - ExpectedExternalID: "", MockResponseBody: `This is an error`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{ @@ -155,17 +218,23 @@ var defaultSendTestCases = []ChannelSendTestCase{ "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `+250788383383Simple Message ☺`, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedMsgStatus: "E", - MockResponseBody: `Error`, MockResponseStatus: 401, + ExpectedMsgStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `Error`, + MockResponseStatus: 401, ExpectedHeaders: map[string]string{ "Content-Type": "application/xml; charset=utf8", "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", }, ExpectedRequestBody: `+250788383383Error Message`, - SendPrep: setSendURL}, + ExpectedMsgStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index b4f3d2e1b..1080aaac3 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -452,49 +452,183 @@ var contactMsg = ` }` var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: helloMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Hello World"), ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - - {Label: "Receive Start Message", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: startMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedEvent: courier.NewConversation, ExpectedURN: "telegram:3527065#nicpottier", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - - {Label: "Receive No Params", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: emptyMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Ignoring"}, - - {Label: "Receive Invalid JSON", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: "foo", ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse"}, - - {Label: "Receive Sticker", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: stickerMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/sticker.jpg"}, ExpectedURN: "telegram:3527065", ExpectedExternalID: "44", ExpectedDate: time.Date(2016, 1, 30, 2, 07, 48, 0, time.UTC)}, - - {Label: "Receive Photo", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: photoMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Photo Caption"), ExpectedAttachments: []string{"/file/bota123/photo.jpg"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "85", ExpectedDate: time.Date(2017, 5, 3, 20, 28, 38, 0, time.UTC)}, - - {Label: "Receive Video", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: videoMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/video.jpg"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "86", ExpectedDate: time.Date(2017, 5, 3, 20, 29, 24, 0, time.UTC)}, - - {Label: "Receive Voice", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: voiceMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/voice.mp4"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "91", ExpectedDate: time.Date(2017, 5, 3, 20, 50, 46, 0, time.UTC)}, - - {Label: "Receive Document", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: documentMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"/file/bota123/document.xls"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "92", ExpectedDate: time.Date(2017, 5, 3, 20, 58, 20, 0, time.UTC)}, - - {Label: "Receive Location", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: locationMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("-2.890287,-79.004333"), ExpectedAttachments: []string{"geo:-2.890287,-79.004333"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "94", ExpectedDate: time.Date(2017, 5, 3, 21, 00, 44, 0, time.UTC)}, - - {Label: "Receive Venue", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: venueMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Cuenca, Provincia del Azuay"), ExpectedAttachments: []string{"geo:-2.898944,-79.006835"}, ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "95", ExpectedDate: time.Date(2017, 5, 3, 21, 05, 20, 0, time.UTC)}, - - {Label: "Receive Contact", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: contactMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), ExpectedMsgText: Sp("Adolf Taxi (0788531373)"), ExpectedURN: "telegram:3527065#nicpottier", ExpectedExternalID: "96", ExpectedDate: time.Date(2017, 5, 3, 21, 9, 15, 0, time.UTC)}, - - {Label: "Receive Empty", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: emptyMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Ignoring"}, - - {Label: "Receive Invalid FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: invalidFileID, ExpectedRespStatus: 200, ExpectedRespBody: "unable to resolve file"}, - - {Label: "Receive NoOk FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: noOkFile, ExpectedRespStatus: 200, ExpectedRespBody: "no 'ok' in response"}, + { - {Label: "Receive NotOk FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: notOkFile, ExpectedRespStatus: 200, ExpectedRespBody: "not present"}, + Label: "Receive Valid Message", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: helloMsg, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedExternalID: "41", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + }, + { - {Label: "Receive No FileID", URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: noFile, ExpectedRespStatus: 200, ExpectedRespBody: "result.file_path"}, + Label: "Receive Start Message", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: startMsg, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedEvent: courier.NewConversation, + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + }, + { + Label: "Receive No Params", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: emptyMsg, + ExpectedRespStatus: 200, + ExpectedRespBody: "Ignoring", + }, + { + Label: "Receive Invalid JSON", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: "foo", + ExpectedRespStatus: 400, + ExpectedRespBody: "unable to parse", + }, + { + Label: "Receive Sticker", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: stickerMsg, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"/file/bota123/sticker.jpg"}, + ExpectedURN: "telegram:3527065", + ExpectedExternalID: "44", + ExpectedDate: time.Date(2016, 1, 30, 2, 07, 48, 0, time.UTC), + }, + { + Label: "Receive Photo", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: photoMsg, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp("Photo Caption"), + ExpectedAttachments: []string{"/file/bota123/photo.jpg"}, + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedExternalID: "85", + ExpectedDate: time.Date(2017, 5, 3, 20, 28, 38, 0, time.UTC), + }, + { + Label: "Receive Video", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: videoMsg, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"/file/bota123/video.jpg"}, + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedExternalID: "86", + ExpectedDate: time.Date(2017, 5, 3, 20, 29, 24, 0, time.UTC), + }, + { + Label: "Receive Voice", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: voiceMsg, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"/file/bota123/voice.mp4"}, + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedExternalID: "91", + ExpectedDate: time.Date(2017, 5, 3, 20, 50, 46, 0, time.UTC), + }, + { + Label: "Receive Document", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: documentMsg, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"/file/bota123/document.xls"}, + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedExternalID: "92", + ExpectedDate: time.Date(2017, 5, 3, 20, 58, 20, 0, time.UTC), + }, + { + Label: "Receive Location", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: locationMsg, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp("-2.890287,-79.004333"), + ExpectedAttachments: []string{"geo:-2.890287,-79.004333"}, + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedExternalID: "94", + ExpectedDate: time.Date(2017, 5, 3, 21, 00, 44, 0, time.UTC), + }, + { + Label: "Receive Venue", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: venueMsg, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp("Cuenca, Provincia del Azuay"), + ExpectedAttachments: []string{"geo:-2.898944,-79.006835"}, + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedExternalID: "95", + ExpectedDate: time.Date(2017, 5, 3, 21, 05, 20, 0, time.UTC), + }, + { + Label: "Receive Contact", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: contactMsg, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp("Adolf Taxi (0788531373)"), + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedExternalID: "96", + ExpectedDate: time.Date(2017, 5, 3, 21, 9, 15, 0, time.UTC), + }, + { + Label: "Receive Empty", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: emptyMsg, + ExpectedRespStatus: 200, + ExpectedRespBody: "Ignoring", + }, + { + Label: "Receive Invalid FileID", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: invalidFileID, + ExpectedRespStatus: 200, + ExpectedRespBody: "unable to resolve file", + }, + { + Label: "Receive NoOk FileID", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: noOkFile, + ExpectedRespStatus: 200, + ExpectedRespBody: "no 'ok' in response", + }, + { + Label: "Receive NotOk FileID", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: notOkFile, + ExpectedRespStatus: 200, + ExpectedRespBody: "not present", + }, + { + Label: "Receive No FileID", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: noFile, + ExpectedRespStatus: 200, + ExpectedRespBody: "result.file_path", + }, } func buildMockTelegramService(testCases []ChannelHandleTestCase) *httptest.Server { diff --git a/handlers/telesom/telesom_test.go b/handlers/telesom/telesom_test.go index c3dc5c30c..8736a368c 100644 --- a/handlers/telesom/telesom_test.go +++ b/handlers/telesom/telesom_test.go @@ -11,29 +11,67 @@ import ( "github.com/nyaruka/gocommon/dates" ) -var ( - receiveValidMessage = "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?mobile=%2B2349067554729&msg=Join" - receiveNoParams = "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" - invalidURN = "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?mobile=MTN&msg=Join" - receiveNoSender = "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?msg=Join" -) - var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TS", "2020", "SO", nil), } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, - {Label: "Invalid URN", URL: invalidURN, Data: "", ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "", ExpectedRespStatus: 400, ExpectedRespBody: "field 'mobile' required"}, - {Label: "Receive No Sender", URL: receiveNoSender, Data: "", ExpectedRespStatus: 400, ExpectedRespBody: "field 'mobile' required"}, - - {Label: "Receive Valid Message", URL: receiveNoParams, Data: "mobile=%2B2349067554729&msg=Join", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, - {Label: "Invalid URN", URL: receiveNoParams, Data: "mobile=MTN&msg=Join", ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "field 'mobile' required"}, - {Label: "Receive No Sender", URL: receiveNoParams, Data: "msg=Join", ExpectedRespStatus: 400, ExpectedRespBody: "field 'mobile' required"}, + { + Label: "Receive Valid Message", + URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?mobile=%2B2349067554729&msg=Join", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + }, + { + Label: "Invalid URN", + URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?mobile=MTN&msg=Join", + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", + }, + { + Label: "Receive No Params", + URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'mobile' required", + }, + { + Label: "Receive No Sender", + URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?msg=Join", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'mobile' required", + }, + { + Label: "Receive Valid Message", + URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + Data: "mobile=%2B2349067554729&msg=Join", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + }, + { + Label: "Invalid URN", + URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + Data: "mobile=MTN&msg=Join", + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", + }, + { + Label: "Receive No Params", + URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + Data: "empty", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'mobile' required", + }, + { + Label: "Receive No Sender", + URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + Data: "msg=Join", + ExpectedRespStatus: 400, + ExpectedRespBody: "field 'mobile' required", + }, } func TestHandler(t *testing.T) { @@ -52,34 +90,51 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+252788383383", - ExpectedMsgStatus: "W", - MockResponseBody: "Success", MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"msg": "Simple Message", "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "D69BB824F88F20482B94ECF3822EBD84"}, - ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: "☺", MsgURN: "tel:+252788383383", - ExpectedMsgStatus: "W", - MockResponseBody: "Success", MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"msg": "☺", "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "60421A7D99BD79FE02697D567315AD0E"}, - ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+252788383383", - ExpectedMsgStatus: "E", - MockResponseBody: "error", MockResponseStatus: 401, - ExpectedURLParams: map[string]string{"msg": `Error Message`, "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "3F1E492B2186551570F24C2F07D5D7E2"}, - ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+252788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedMsgStatus: "W", - MockResponseBody: `Success`, MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"msg": "My pic!\nhttps://foo.bar/image.jpg", "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "DBE569579FD899628C17254ECCE15DB7"}, - ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - SendPrep: setSendURL}, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+252788383383", + MockResponseBody: "Success", + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"msg": "Simple Message", "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "D69BB824F88F20482B94ECF3822EBD84"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + ExpectedMsgStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "tel:+252788383383", + MockResponseBody: "Success", + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"msg": "☺", "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "60421A7D99BD79FE02697D567315AD0E"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + ExpectedMsgStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+252788383383", + MockResponseBody: "error", + MockResponseStatus: 401, + ExpectedURLParams: map[string]string{"msg": `Error Message`, "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "3F1E492B2186551570F24C2F07D5D7E2"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + ExpectedMsgStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+252788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `Success`, + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"msg": "My pic!\nhttps://foo.bar/image.jpg", "to": "0788383383", "from": "2020", "username": "Username", "password": "Password", "key": "DBE569579FD899628C17254ECCE15DB7"}, + ExpectedHeaders: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + ExpectedMsgStatus: "W", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { From 68527f3dd0f0c62570fc961305d4e86057a1f6a3 Mon Sep 17 00:00:00 2001 From: Robi9 Date: Fri, 2 Sep 2022 16:00:02 -0300 Subject: [PATCH 123/294] Add support for sending captioned attachments --- handlers/facebookapp/facebookapp.go | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 871923711..5f8b4863d 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -1012,11 +1012,11 @@ type wacTemplate struct { type wacInteractive struct { Type string `json:"type"` Header *struct { - Type string `json:"type"` - Text string `json:"text,omitempty"` - Video string `json:"video,omitempty"` - Image string `json:"image,omitempty"` - Document string `json:"document,omitempty"` + Type string `json:"type"` + Text string `json:"text,omitempty"` + Video *wacMTMedia `json:"video,omitempty"` + Image *wacMTMedia `json:"image,omitempty"` + Document *wacMTMedia `json:"document,omitempty"` } `json:"header,omitempty"` Body struct { Text string `json:"text"` @@ -1065,6 +1065,8 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + hasCaption := false + msgParts := make([]string, 0) if msg.Text() != "" { msgParts = handlers.SplitMsgByChannel(msg.Channel(), msg.Text(), maxMsgLength) @@ -1177,6 +1179,11 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, payload.Type = attType media := wacMTMedia{Link: attURL} + if len(msgParts) == 1 && attType != "audio" && len(msg.Attachments()) == 1 && len(msg.QuickReplies()) == 0 { + media.Caption = msgParts[i] + hasCaption = true + } + if attType == "image" { payload.Image = &media } else if attType == "audio" { @@ -1292,6 +1299,10 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, // this was wired successfully status.SetStatus(courier.MsgWired) + if hasCaption { + break + } + } return status, nil } From 864cb5f17173f1c500d5406624d05e7fcb76a07b Mon Sep 17 00:00:00 2001 From: Robi9 Date: Fri, 2 Sep 2022 16:00:51 -0300 Subject: [PATCH 124/294] Add tests for sending attachments with captions --- handlers/facebookapp/facebookapp_test.go | 90 +++++++++--------------- 1 file changed, 33 insertions(+), 57 deletions(-) diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 7eab23752..e64b981a6 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -1158,67 +1158,43 @@ var SendTestCasesWAC = []ChannelSendTestCase{ SendPrep: setSendURL, }, { - Label: "Document Send", - MsgText: "document caption", - MsgURN: "whatsapp:250788123123", - MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, - MockResponses: map[MockedRequest]*httpx.MockResponse{ - { - Method: "POST", - Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"document","document":{"link":"https://foo.bar/document.pdf"}}`, - }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), - { - Method: "POST", - Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"document caption","preview_url":false}}`, - }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), - }, - ExpectedMsgStatus: "W", - ExpectedExternalID: "157b5e14568e8", - SendPrep: setSendURL, + Label: "Document Send", + MsgText: "document caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"document","document":{"link":"https://foo.bar/document.pdf","caption":"document caption"}}`, + ExpectedRequestPath: "/12345_ID/messages", + ExpectedMsgStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, { - Label: "Image Send", - MsgText: "document caption", - MsgURN: "whatsapp:250788123123", - MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MockResponses: map[MockedRequest]*httpx.MockResponse{ - { - Method: "POST", - Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, - }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), - { - Method: "POST", - Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"document caption","preview_url":false}}`, - }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), - }, - ExpectedMsgStatus: "W", - ExpectedExternalID: "157b5e14568e8", - SendPrep: setSendURL, + Label: "Image Send", + MsgText: "image caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg","caption":"image caption"}}`, + ExpectedRequestPath: "/12345_ID/messages", + ExpectedMsgStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, { - Label: "Video Send", - MsgText: "video caption", - MsgURN: "whatsapp:250788123123", - MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, - MockResponses: map[MockedRequest]*httpx.MockResponse{ - { - Method: "POST", - Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"video","video":{"link":"https://foo.bar/video.mp4"}}`, - }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), - { - Method: "POST", - Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"video caption","preview_url":false}}`, - }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), - }, - ExpectedMsgStatus: "W", - ExpectedExternalID: "157b5e14568e8", - SendPrep: setSendURL, + Label: "Video Send", + MsgText: "video caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"video","video":{"link":"https://foo.bar/video.mp4","caption":"video caption"}}`, + ExpectedRequestPath: "/12345_ID/messages", + ExpectedMsgStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, }, { Label: "Template Send", From 507a69c8733128630088945158b0d67ae27fa65e Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 5 Sep 2022 07:39:14 -0700 Subject: [PATCH 125/294] Add codecov token to ci.yml --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0c468dd84..e2b6dd812 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,8 @@ jobs: if: success() uses: codecov/codecov-action@v2 with: - fail_ci_if_error: false + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true release: name: Release From 703ed51815ea685ee0cc0575ba546b0bf27425bd Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 5 Sep 2022 10:58:18 -0500 Subject: [PATCH 126/294] Update CHANGELOG.md for v7.5.21 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79bcbbdee..0c234f8ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +v7.5.21 +---------- + * Add codecov token to ci.yml + * Add WAC support for sending captioned attachments + * Cleanup tests + * Include requests made by DescribeURN methods in the channel log for a receive + v7.5.20 ---------- * Fix writing errors to channel logs From 24462385ae0769276fd3cfe8bec2a52094ee8ae0 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 5 Sep 2022 11:20:39 -0500 Subject: [PATCH 127/294] Save channel logs with UUID --- backends/rapidpro/channel_log.go | 8 +++++--- backends/rapidpro/schema.sql | 1 + channel_log.go | 9 ++++++--- channel_log_test.go | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/backends/rapidpro/channel_log.go b/backends/rapidpro/channel_log.go index 25e54d702..1eb3feb55 100644 --- a/backends/rapidpro/channel_log.go +++ b/backends/rapidpro/channel_log.go @@ -3,7 +3,6 @@ package rapidpro import ( "context" "encoding/json" - "time" "github.com/nyaruka/courier" @@ -11,11 +10,12 @@ import ( ) const insertLogSQL = ` -INSERT INTO channels_channellog( log_type, channel_id, msg_id, http_logs, errors, is_error, created_on, elapsed_ms) - VALUES(:log_type, :channel_id, :msg_id, :http_logs, :errors, :is_error, :created_on, :elapsed_ms)` +INSERT INTO channels_channellog( uuid, log_type, channel_id, msg_id, http_logs, errors, is_error, created_on, elapsed_ms) + VALUES(:uuid, :log_type, :channel_id, :msg_id, :http_logs, :errors, :is_error, :created_on, :elapsed_ms)` // ChannelLog is our DB specific struct for logs type ChannelLog struct { + UUID courier.ChannelLogUUID `db:"uuid"` Type courier.ChannelLogType `db:"log_type"` ChannelID courier.ChannelID `db:"channel_id"` MsgID courier.MsgID `db:"msg_id"` @@ -40,6 +40,7 @@ type channelError struct { func queueChannelLog(ctx context.Context, b *backend, clog *courier.ChannelLog) error { dbChan := clog.Channel().(*DBChannel) + // if we have an error or a non 2XX/3XX http response then this log is marked as an error isError := len(clog.Errors()) > 0 if !isError { for _, l := range clog.HTTPLogs() { @@ -57,6 +58,7 @@ func queueChannelLog(ctx context.Context, b *backend, clog *courier.ChannelLog) // create our value for committing v := &ChannelLog{ + UUID: clog.UUID(), Type: clog.Type(), ChannelID: dbChan.ID(), MsgID: clog.MsgID(), diff --git a/backends/rapidpro/schema.sql b/backends/rapidpro/schema.sql index d137f146a..0cf782dd0 100644 --- a/backends/rapidpro/schema.sql +++ b/backends/rapidpro/schema.sql @@ -87,6 +87,7 @@ CREATE TABLE msgs_msg ( DROP TABLE IF EXISTS channels_channellog CASCADE; CREATE TABLE channels_channellog ( id serial primary key, + uuid uuid NOT NULL, channel_id integer NOT NULL references channels_channel(id) on delete cascade, msg_id bigint references msgs_msg(id) on delete cascade, log_type character varying(16), diff --git a/channel_log.go b/channel_log.go index 2c68d5218..31abeae9f 100644 --- a/channel_log.go +++ b/channel_log.go @@ -8,6 +8,9 @@ import ( "github.com/nyaruka/gocommon/uuids" ) +// ChannelLogUUID is our type for a channel log UUID +type ChannelLogUUID uuids.UUID + // ChannelLogType is the type of channel interaction we are logging type ChannelLogType string @@ -40,7 +43,7 @@ func (e *ChannelError) Code() string { // ChannelLog stores the HTTP traces and errors generated by an interaction with a channel. type ChannelLog struct { - uuid uuids.UUID + uuid ChannelLogUUID type_ ChannelLogType channel Channel msgID MsgID @@ -69,7 +72,7 @@ func NewChannelLog(t ChannelLogType, ch Channel) *ChannelLog { func newChannelLog(t ChannelLogType, ch Channel, r *httpx.Recorder, mid MsgID) *ChannelLog { return &ChannelLog{ - uuid: uuids.New(), + uuid: ChannelLogUUID(uuids.New()), type_: t, channel: ch, recorder: r, @@ -96,7 +99,7 @@ func (l *ChannelLog) End() { l.elapsed = time.Since(l.createdOn) } -func (l *ChannelLog) UUID() uuids.UUID { +func (l *ChannelLog) UUID() ChannelLogUUID { return l.uuid } diff --git a/channel_log_test.go b/channel_log_test.go index 84e35ad9f..cae5f279a 100644 --- a/channel_log_test.go +++ b/channel_log_test.go @@ -44,7 +44,7 @@ func TestChannelLog(t *testing.T) { clog.Error(errors.New("this is an error")) clog.End() - assert.Equal(t, uuids.UUID("c00e5d67-c275-4389-aded-7d8b151cbd5b"), clog.UUID()) + assert.Equal(t, courier.ChannelLogUUID("c00e5d67-c275-4389-aded-7d8b151cbd5b"), clog.UUID()) assert.Equal(t, courier.ChannelLogTypeTokenFetch, clog.Type()) assert.Equal(t, channel, clog.Channel()) assert.Equal(t, courier.NilMsgID, clog.MsgID()) From 1d0738e37f4508eda6aadfa3c7f9136141ecba45 Mon Sep 17 00:00:00 2001 From: Robi9 Date: Mon, 5 Sep 2022 14:28:25 -0300 Subject: [PATCH 128/294] Remove expiration_timestamp from moPayload in WAC --- handlers/facebookapp/facebookapp.go | 1 - 1 file changed, 1 deletion(-) diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 1d28e558a..2efff1c3f 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -198,7 +198,6 @@ type moPayload struct { Origin *struct { Type string `json:"type"` } `json:"origin"` - ExpirationTimestamp int64 `json:"expiration_timestamp"` } `json:"conversation"` Pricing *struct { PricingModel string `json:"pricing_model"` From 65f288a4d67b0d277a9e299ff9f29f96ea763dbb Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 5 Sep 2022 17:42:09 -0500 Subject: [PATCH 129/294] Update CHANGELOG.md for v7.5.22 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c234f8ef..906788647 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.22 +---------- + * Save channel logs with UUID + v7.5.21 ---------- * Add codecov token to ci.yml From 9b381ecc801f9518a2ecdf3b9b4598e3bd0f2e67 Mon Sep 17 00:00:00 2001 From: Robi9 Date: Tue, 6 Sep 2022 11:41:23 -0300 Subject: [PATCH 130/294] Add interactive message support with attachments, quick replies and captions. --- handlers/facebookapp/facebookapp.go | 243 ++++++++++++++++++---------- 1 file changed, 154 insertions(+), 89 deletions(-) diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 1d28e558a..a9bd15551 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -1073,6 +1073,8 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, } qrs := msg.QuickReplies() + var payloadAudio wacMTPayload + for i := 0; i < len(msgParts)+len(msg.Attachments()); i++ { payload := wacMTPayload{MessagingProduct: "whatsapp", RecipientType: "individual", To: msg.URN().Path()} @@ -1170,7 +1172,7 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, } } - } else if i < len(msg.Attachments()) { + } else if i < len(msg.Attachments()) && len(qrs) == 0 || len(qrs) > 3 && i < len(msg.Attachments()) { attType, attURL := handlers.SplitAttachment(msg.Attachments()[i]) attType = strings.Split(attType, "/")[0] if attType == "application" { @@ -1194,116 +1196,179 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, payload.Document = &media } } else { - if i < (len(msgParts) + len(msg.Attachments()) - 1) { - // this is still a msg part - text := &wacText{PreviewURL: false} - payload.Type = "text" - if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") { - text.PreviewURL = true - } - text.Body = msgParts[i-len(msg.Attachments())] - payload.Text = text - } else { - if len(qrs) > 0 { - payload.Type = "interactive" - // We can use buttons - if len(qrs) <= 3 { - interactive := wacInteractive{Type: "button", Body: struct { - Text string "json:\"text\"" - }{Text: msgParts[i-len(msg.Attachments())]}} - - btns := make([]wacMTButton, len(qrs)) - for i, qr := range qrs { - btns[i] = wacMTButton{ - Type: "reply", + if len(qrs) > 0 { + payload.Type = "interactive" + // We can use buttons + if len(qrs) <= 3 { + interactive := wacInteractive{Type: "button", Body: struct { + Text string "json:\"text\"" + }{Text: msgParts[i]}} + + if len(msg.Attachments()) > 0 { + hasCaption = true + attType, attURL := handlers.SplitAttachment(msg.Attachments()[i]) + attType = strings.Split(attType, "/")[0] + if attType == "application" { + attType = "document" + } + if attType == "image" { + image := wacMTMedia{ + Link: attURL, + } + interactive.Header = &struct { + Type string "json:\"type\"" + Text string "json:\"text,omitempty\"" + Video *wacMTMedia "json:\"video,omitempty\"" + Image *wacMTMedia "json:\"image,omitempty\"" + Document *wacMTMedia "json:\"document,omitempty\"" + }{Type: "image", Image: &image} + } else if attType == "video" { + video := wacMTMedia{ + Link: attURL, + } + interactive.Header = &struct { + Type string "json:\"type\"" + Text string "json:\"text,omitempty\"" + Video *wacMTMedia "json:\"video,omitempty\"" + Image *wacMTMedia "json:\"image,omitempty\"" + Document *wacMTMedia "json:\"document,omitempty\"" + }{Type: "video", Video: &video} + } else if attType == "document" { + filename, err := utils.BasePathForURL(attURL) + if err != nil { + return nil, err + } + document := wacMTMedia{ + Link: attURL, + Filename: filename, + } + interactive.Header = &struct { + Type string "json:\"type\"" + Text string "json:\"text,omitempty\"" + Video *wacMTMedia "json:\"video,omitempty\"" + Image *wacMTMedia "json:\"image,omitempty\"" + Document *wacMTMedia "json:\"document,omitempty\"" + }{Type: "document", Document: &document} + } else if attType == "audio" { + var zeroIndex bool + if i == 0 { + zeroIndex = true } - btns[i].Reply.ID = fmt.Sprint(i) - btns[i].Reply.Title = qr + payloadAudio = wacMTPayload{MessagingProduct: "whatsapp", RecipientType: "individual", To: msg.URN().Path(), Type: "audio", Audio: &wacMTMedia{Link: attURL}} + status, err := requestWAC(payloadAudio, accessToken, status, wacPhoneURL, zeroIndex, clog) + if err != nil { + return status, nil + } + } else { + interactive.Type = "button" + interactive.Body.Text = msgParts[i] } - interactive.Action = &struct { - Button string "json:\"button,omitempty\"" - Sections []wacMTSection "json:\"sections,omitempty\"" - Buttons []wacMTButton "json:\"buttons,omitempty\"" - }{Buttons: btns} - payload.Interactive = &interactive - - } else if len(qrs) <= 10 { - interactive := wacInteractive{Type: "list", Body: struct { - Text string "json:\"text\"" - }{Text: msgParts[i-len(msg.Attachments())]}} - - section := wacMTSection{ - Rows: make([]wacMTSectionRow, len(qrs)), + } + + btns := make([]wacMTButton, len(qrs)) + for i, qr := range qrs { + btns[i] = wacMTButton{ + Type: "reply", } - for i, qr := range qrs { - section.Rows[i] = wacMTSectionRow{ - ID: fmt.Sprint(i), - Title: qr, - } + btns[i].Reply.ID = fmt.Sprint(i) + btns[i].Reply.Title = qr + } + interactive.Action = &struct { + Button string "json:\"button,omitempty\"" + Sections []wacMTSection "json:\"sections,omitempty\"" + Buttons []wacMTButton "json:\"buttons,omitempty\"" + }{Buttons: btns} + payload.Interactive = &interactive + + } else if len(qrs) <= 10 { + interactive := wacInteractive{Type: "list", Body: struct { + Text string "json:\"text\"" + }{Text: msgParts[i-len(msg.Attachments())]}} + + section := wacMTSection{ + Rows: make([]wacMTSectionRow, len(qrs)), + } + for i, qr := range qrs { + section.Rows[i] = wacMTSectionRow{ + ID: fmt.Sprint(i), + Title: qr, } + } - interactive.Action = &struct { - Button string "json:\"button,omitempty\"" - Sections []wacMTSection "json:\"sections,omitempty\"" - Buttons []wacMTButton "json:\"buttons,omitempty\"" - }{Button: "Menu", Sections: []wacMTSection{ - section, - }} + interactive.Action = &struct { + Button string "json:\"button,omitempty\"" + Sections []wacMTSection "json:\"sections,omitempty\"" + Buttons []wacMTButton "json:\"buttons,omitempty\"" + }{Button: "Menu", Sections: []wacMTSection{ + section, + }} - payload.Interactive = &interactive - } else { - return nil, fmt.Errorf("too many quick replies WAC supports only up to 10 quick replies") - } + payload.Interactive = &interactive } else { - // this is still a msg part - text := &wacText{PreviewURL: false} - payload.Type = "text" - if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") { - text.PreviewURL = true - } - text.Body = msgParts[i-len(msg.Attachments())] - payload.Text = text + return nil, fmt.Errorf("too many quick replies WAC supports only up to 10 quick replies") + } + } else { + // this is still a msg part + text := &wacText{PreviewURL: false} + payload.Type = "text" + if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") { + text.PreviewURL = true } + text.Body = msgParts[i-len(msg.Attachments())] + payload.Text = text } + } + var zeroIndex bool + if i == 0 { + zeroIndex = true } - jsonBody, err := json.Marshal(payload) + status, err := requestWAC(payload, accessToken, status, wacPhoneURL, zeroIndex, clog) if err != nil { return status, err } - req, err := http.NewRequest(http.MethodPost, wacPhoneURL.String(), bytes.NewReader(jsonBody)) - if err != nil { - return nil, err + if hasCaption { + break } - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken)) - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Accept", "application/json") + } + return status, nil +} - resp, respBody, err := handlers.RequestHTTP(req, clog) - if err != nil || resp.StatusCode/100 != 2 { - return status, nil - } +func requestWAC(payload wacMTPayload, accessToken string, status courier.MsgStatus, wacPhoneURL *url.URL, zeroIndex bool, clog *courier.ChannelLog) (courier.MsgStatus, error) { + jsonBody, err := json.Marshal(payload) + if err != nil { + return status, err + } - respPayload := &wacMTResponse{} - err = json.Unmarshal(respBody, respPayload) - if err != nil { - clog.Error(errors.Errorf("unable to unmarshal response body")) - return status, nil - } - externalID := respPayload.Messages[0].ID - if i == 0 && externalID != "" { - status.SetExternalID(externalID) - } - // this was wired successfully - status.SetStatus(courier.MsgWired) + req, err := http.NewRequest(http.MethodPost, wacPhoneURL.String(), bytes.NewReader(jsonBody)) + if err != nil { + return nil, err + } - if hasCaption { - break - } + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") + + resp, respBody, err := handlers.RequestHTTP(req, clog) + if err != nil || resp.StatusCode/100 != 2 { + return status, nil + } + + respPayload := &wacMTResponse{} + err = json.Unmarshal(respBody, respPayload) + if err != nil { + clog.Error(errors.Errorf("unable to unmarshal response body")) + return status, nil + } + externalID := respPayload.Messages[0].ID + if zeroIndex && externalID != "" { + status.SetExternalID(externalID) } + // this was wired successfully + status.SetStatus(courier.MsgWired) return status, nil } From 24507aa05250240942d4bba6f6fdb30ae7d9aada Mon Sep 17 00:00:00 2001 From: Robi9 Date: Tue, 6 Sep 2022 11:42:26 -0300 Subject: [PATCH 131/294] Adjust test cases for interactive messages --- handlers/facebookapp/facebookapp_test.go | 52 +++++++++++++++++++++--- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index e64b981a6..8b41e9bba 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -1252,21 +1252,63 @@ var SendTestCasesWAC = []ChannelSendTestCase{ SendPrep: setSendURL, }, { - Label: "Interactive Button Message Send with attachment", + Label: "Interactive Button Message Send with image attachment", + MsgText: "Interactive Button Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"BUTTON1"}, + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","header":{"type":"image","image":{"link":"https://foo.bar/image.jpg"}},"body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, + ExpectedRequestPath: "/12345_ID/messages", + ExpectedMsgStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Interactive Button Message Send with video attachment", + MsgText: "Interactive Button Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"BUTTON1"}, + MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","header":{"type":"video","video":{"link":"https://foo.bar/video.mp4"}},"body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, + ExpectedRequestPath: "/12345_ID/messages", + ExpectedMsgStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Interactive Button Message Send with document attachment", + MsgText: "Interactive Button Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"BUTTON1"}, + MsgAttachments: []string{"document/pdf:https://foo.bar/document.pdf"}, + MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, + MockResponseStatus: 201, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","header":{"type":"document","document":{"link":"https://foo.bar/document.pdf","filename":"document.pdf"}},"body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, + ExpectedRequestPath: "/12345_ID/messages", + ExpectedMsgStatus: "W", + ExpectedExternalID: "157b5e14568e8", + SendPrep: setSendURL, + }, + { + Label: "Interactive Button Message Send with audio attachment", MsgText: "Interactive Button Msg", MsgURN: "whatsapp:250788123123", - MsgQuickReplies: []string{"BUTTON1"}, - MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MsgQuickReplies: []string{"ROW1", "ROW2", "ROW3"}, + MsgAttachments: []string{"audio/mp3:https://foo.bar/audio.mp3"}, MockResponses: map[MockedRequest]*httpx.MockResponse{ { Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"audio","audio":{"link":"https://foo.bar/audio.mp3"}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), { Method: "POST", Path: "/12345_ID/messages", - Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"ROW1"}},{"type":"reply","reply":{"id":"1","title":"ROW2"}},{"type":"reply","reply":{"id":"2","title":"ROW3"}}]}}}`, }: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), }, ExpectedMsgStatus: "W", From e0c0da0be6bd8ec78c1f671e71d57c06eb71d70c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 6 Sep 2022 10:31:38 -0500 Subject: [PATCH 132/294] Support channels receiving embedded attachments and use with thinq handler --- backends/rapidpro/backend_test.go | 12 +++++++ backends/rapidpro/msg.go | 53 +++++++++++++++++++++++-------- handlers/thinq/thinq.go | 13 +++++++- msg.go | 1 + test/msg.go | 13 ++++++++ 5 files changed, 78 insertions(+), 14 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 26e5445a5..ca20bc8df 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -1068,6 +1068,18 @@ func (ts *BackendTestSuite) TestWriteAttachment() { ts.True(strings.HasPrefix(m.Attachments()[0], "image/png:")) ts.True(strings.HasSuffix(m.Attachments()[0], ".png")) } + + // try embedded attachment + msg = ts.b.NewIncomingMsg(knChannel, urn, "embedded attachment").(*DBMsg) + msg.WithEmbeddedAttachment("image/jpeg", []byte("jpegdata"), "jpg") + + err = ts.b.WriteMsg(ctx, msg, clog) + ts.NoError(err) + + ts.Equal(1, len(msg.Attachments())) + ts.True(strings.HasPrefix(msg.Attachments()[0], "image/jpeg:")) + ts.True(strings.HasSuffix(msg.Attachments()[0], ".jpg")) + } func (ts *BackendTestSuite) TestWriteMsg() { diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index 5a6dc74ab..a40c145a1 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -59,10 +59,10 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch channel := m.Channel() - // if we have media, go download it to S3 + // if we have attachment URLs, download them to our own storage for i, attachment := range m.Attachments_ { if strings.HasPrefix(attachment, "http") { - url, err := downloadMediaToS3(ctx, b, channel, m.OrgID_, m.UUID_, attachment) + url, err := downloadAttachmentToStorage(ctx, b, channel, m.OrgID_, m.UUID_, attachment) if err != nil { return err } @@ -70,6 +70,15 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch } } + // if we have embedded attachments, save them to our own storage and add URLs to the message + for _, ea := range m.embeddedAttachments { + url, err := saveAttachmentToStorage(ctx, b, m.OrgID_, m.UUID_, ea.contentType, ea.data, ea.ext) + if err != nil { + return err + } + m.Attachments_ = append(m.Attachments_, url) + } + // try to write it our db err := writeMsgToDB(ctx, b, m, clog) @@ -213,12 +222,11 @@ WHERE ` //----------------------------------------------------------------------------- -// Media download and classification +// Attachment download and classification //----------------------------------------------------------------------------- -func downloadMediaToS3(ctx context.Context, b *backend, channel courier.Channel, orgID OrgID, msgUUID courier.MsgUUID, mediaURL string) (string, error) { - - parsedURL, err := url.Parse(mediaURL) +func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courier.Channel, orgID OrgID, msgUUID courier.MsgUUID, attURL string) (string, error) { + parsedURL, err := url.Parse(attURL) if err != nil { return "", err } @@ -232,14 +240,14 @@ func downloadMediaToS3(ctx context.Context, b *backend, channel courier.Channel, // in the case of errors, we log the error but move onwards anyways if err != nil { - logrus.WithField("channel_uuid", channel.UUID()).WithField("channel_type", channel.ChannelType()).WithField("media_url", mediaURL).WithError(err).Error("unable to build media download request") + logrus.WithField("channel_uuid", channel.UUID()).WithField("channel_type", channel.ChannelType()).WithField("media_url", attURL).WithError(err).Error("unable to build attachment download request") } } } if req == nil { // first fetch our media - req, err = http.NewRequest(http.MethodGet, mediaURL, nil) + req, err = http.NewRequest(http.MethodGet, attURL, nil) if err != nil { return "", err } @@ -262,7 +270,7 @@ func downloadMediaToS3(ctx context.Context, b *backend, channel courier.Channel, } // first try getting our mime type from the first 300 bytes of our body - fileType, err := filetype.Match(body[:300]) + fileType, _ := filetype.Match(body[:300]) if fileType != filetype.Unknown { mimeType = fileType.MIME.Value extension = fileType.Extension @@ -288,23 +296,28 @@ func downloadMediaToS3(ctx context.Context, b *backend, channel courier.Channel, } } + return saveAttachmentToStorage(ctx, b, orgID, msgUUID, mimeType, body, extension) +} + +func saveAttachmentToStorage(ctx context.Context, b *backend, orgID OrgID, msgUUID courier.MsgUUID, contentType string, data []byte, ext string) (string, error) { // create our filename filename := msgUUID.String() - if extension != "" { - filename = fmt.Sprintf("%s.%s", msgUUID, extension) + if ext != "" { + filename = fmt.Sprintf("%s.%s", msgUUID, ext) } + path := filepath.Join(b.config.S3AttachmentsPrefix, strconv.FormatInt(int64(orgID), 10), filename[:4], filename[4:8], filename) if !strings.HasPrefix(path, "/") { path = fmt.Sprintf("/%s", path) } - s3URL, err := b.storage.Put(ctx, path, mimeType, body) + s3URL, err := b.storage.Put(ctx, path, contentType, data) if err != nil { return "", err } // return our new media URL, which is prefixed by our content type - return fmt.Sprintf("%s:%s", mimeType, s3URL), nil + return fmt.Sprintf("%s:%s", contentType, s3URL), nil } //----------------------------------------------------------------------------- @@ -478,6 +491,12 @@ func writeExternalIDSeen(b *backend, msg courier.Msg) { // Our implementation of Msg interface //----------------------------------------------------------------------------- +type embeddedAttachment struct { + contentType string + data []byte + ext string +} + // DBMsg is our base struct to represent msgs both in our JSON and db representations type DBMsg struct { OrgID_ OrgID `json:"org_id" db:"org_id"` @@ -525,6 +544,8 @@ type DBMsg struct { workerToken queue.WorkerToken alreadyWritten bool quickReplies []string + + embeddedAttachments []*embeddedAttachment } func (m *DBMsg) ID() courier.MsgID { return m.ID_ } @@ -625,6 +646,12 @@ func (m *DBMsg) WithAttachment(url string) courier.Msg { return m } +// WithEmbeddedAttachment can be used to add an embedded attachment to a message +func (m *DBMsg) WithEmbeddedAttachment(contentType string, data []byte, ext string) courier.Msg { + m.embeddedAttachments = append(m.embeddedAttachments, &embeddedAttachment{contentType, data, ext}) + return m +} + // WithURNAuth can be used to add a URN auth setting to a message func (m *DBMsg) WithURNAuth(auth string) courier.Msg { m.URNAuth_ = auth diff --git a/handlers/thinq/thinq.go b/handlers/thinq/thinq.go index 9f16d55ef..95d680480 100644 --- a/handlers/thinq/thinq.go +++ b/handlers/thinq/thinq.go @@ -3,6 +3,7 @@ package thinq import ( "bytes" "context" + "encoding/base64" "encoding/json" "errors" "fmt" @@ -70,10 +71,20 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } var msg courier.Msg + if form.Type == "sms" { msg = h.Backend().NewIncomingMsg(channel, urn, form.Message) } else if form.Type == "mms" { - msg = h.Backend().NewIncomingMsg(channel, urn, "").WithAttachment(form.Message) + if strings.HasPrefix(form.Message, "http://") || strings.HasPrefix(form.Message, "https://") { + msg = h.Backend().NewIncomingMsg(channel, urn, "").WithAttachment(form.Message) + } else { + imgData, err := base64.StdEncoding.DecodeString(form.Message) + if err != nil { + clog.Error(errors.New("unable to decode MMS data")) + return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, errors.New("unable to decode MMS data")) + } + msg = h.Backend().NewIncomingMsg(channel, urn, "").WithEmbeddedAttachment("image/jpeg", imgData, "jpg") + } } else { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, fmt.Errorf("unknown message type: %s", form.Type)) } diff --git a/msg.go b/msg.go index c94dd6491..43c4e0104 100644 --- a/msg.go +++ b/msg.go @@ -120,6 +120,7 @@ type Msg interface { WithID(id MsgID) Msg WithUUID(uuid MsgUUID) Msg WithAttachment(url string) Msg + WithEmbeddedAttachment(contentType string, data []byte, ext string) Msg WithURNAuth(auth string) Msg WithMetadata(metadata json.RawMessage) Msg WithFlow(flow *FlowReference) Msg diff --git a/test/msg.go b/test/msg.go index 7ab7b76b7..799d0eaac 100644 --- a/test/msg.go +++ b/test/msg.go @@ -8,6 +8,12 @@ import ( "github.com/nyaruka/gocommon/urns" ) +type mockEmbeddedAttachment struct { + contentType string + data []byte + ext string +} + type mockMsg struct { id courier.MsgID uuid courier.MsgUUID @@ -16,6 +22,7 @@ type mockMsg struct { urnAuth string text string attachments []string + embeddedAttachments []*mockEmbeddedAttachment externalID string contactName string highPriority bool @@ -87,10 +94,16 @@ func (m *mockMsg) WithReceivedOn(date time.Time) courier.Msg { m.receivedOn = &d func (m *mockMsg) WithExternalID(id string) courier.Msg { m.externalID = id; return m } func (m *mockMsg) WithID(id courier.MsgID) courier.Msg { m.id = id; return m } func (m *mockMsg) WithUUID(uuid courier.MsgUUID) courier.Msg { m.uuid = uuid; return m } + func (m *mockMsg) WithAttachment(url string) courier.Msg { m.attachments = append(m.attachments, url) return m } +func (m *mockMsg) WithEmbeddedAttachment(contentType string, data []byte, ext string) courier.Msg { + m.embeddedAttachments = append(m.embeddedAttachments, &mockEmbeddedAttachment{contentType, data, ext}) + return m +} + func (m *mockMsg) WithMetadata(metadata json.RawMessage) courier.Msg { m.metadata = metadata; return m } func (m *mockMsg) WithFlow(flow *courier.FlowReference) courier.Msg { m.flow = flow; return m } From b8e9114afcbc1e90079313a036b9e7342bb71c85 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 6 Sep 2022 11:22:21 -0500 Subject: [PATCH 133/294] Add test case for thinq incoming with base64 encoded image --- backends/rapidpro/msg.go | 8 ++++---- handlers/test.go | 2 ++ handlers/thinq/thinq.go | 1 + handlers/thinq/thinq_test.go | 22 +++++++++++++++++++--- msg.go | 2 +- test/msg.go | 12 +++--------- test/testdata/test.jpg | Bin 0 -> 17301 bytes 7 files changed, 30 insertions(+), 17 deletions(-) create mode 100644 test/testdata/test.jpg diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index a40c145a1..47c7e811a 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -72,7 +72,7 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch // if we have embedded attachments, save them to our own storage and add URLs to the message for _, ea := range m.embeddedAttachments { - url, err := saveAttachmentToStorage(ctx, b, m.OrgID_, m.UUID_, ea.contentType, ea.data, ea.ext) + url, err := saveAttachmentToStorage(ctx, b, m.OrgID_, m.UUID_, ea.contentType, ea.data, ea.extension) if err != nil { return err } @@ -494,7 +494,7 @@ func writeExternalIDSeen(b *backend, msg courier.Msg) { type embeddedAttachment struct { contentType string data []byte - ext string + extension string } // DBMsg is our base struct to represent msgs both in our JSON and db representations @@ -647,8 +647,8 @@ func (m *DBMsg) WithAttachment(url string) courier.Msg { } // WithEmbeddedAttachment can be used to add an embedded attachment to a message -func (m *DBMsg) WithEmbeddedAttachment(contentType string, data []byte, ext string) courier.Msg { - m.embeddedAttachments = append(m.embeddedAttachments, &embeddedAttachment{contentType, data, ext}) +func (m *DBMsg) WithEmbeddedAttachment(contentType string, data []byte, extension string) courier.Msg { + m.embeddedAttachments = append(m.embeddedAttachments, &embeddedAttachment{contentType: contentType, data: data, extension: extension}) return m } diff --git a/handlers/test.go b/handlers/test.go index d5f9c9d70..f76db682c 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -407,9 +407,11 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri require.Equal(tc.ExpectedMsgID, -1) } } + if len(tc.ExpectedAttachments) > 0 { require.Equal(tc.ExpectedAttachments, msg.Attachments()) } + if !tc.ExpectedDate.IsZero() { if msg != nil { require.Equal((tc.ExpectedDate).Local(), (*msg.ReceivedOn()).Local()) diff --git a/handlers/thinq/thinq.go b/handlers/thinq/thinq.go index 95d680480..85a9d86da 100644 --- a/handlers/thinq/thinq.go +++ b/handlers/thinq/thinq.go @@ -44,6 +44,7 @@ func (h *handler) Initialize(s courier.Server) error { return nil } +// see https://apidocs.thinq.com/#829c8863-8a47-4273-80fb-d962aa64c901 // from: Source DID // to: Destination DID // type: sms|mms diff --git a/handlers/thinq/thinq_test.go b/handlers/thinq/thinq_test.go index d5a7577cb..e14be7f0d 100644 --- a/handlers/thinq/thinq_test.go +++ b/handlers/thinq/thinq_test.go @@ -1,7 +1,10 @@ package thinq import ( + "encoding/base64" + "fmt" "net/http/httptest" + "net/url" "testing" "github.com/nyaruka/courier" @@ -18,6 +21,11 @@ const ( statusURL = "/c/tq/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/" ) +func base64Attachment(path string) string { + data := test.ReadFile(path) + return base64.StdEncoding.EncodeToString(data) +} + var testCases = []ChannelHandleTestCase{ { Label: "Receive Valid", @@ -36,15 +44,23 @@ var testCases = []ChannelHandleTestCase{ ExpectedRespBody: `'From' failed on the 'required'`, }, { - Label: "Receive Media", + Label: "Receive attachment as URL", URL: receiveURL, - Data: "message=http://foo.bar/foo.png&hello+world&from=2065551234&type=mms&to=2065551212", + Data: "message=http://foo.bar/foo.png&from=2065551234&type=mms&to=2065551212", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedURN: "tel:+12065551234", ExpectedAttachments: []string{"http://foo.bar/foo.png"}, }, - + { + Label: "Receive attachment as base64", + URL: receiveURL, + Data: fmt.Sprintf("message=%s&from=2065551234&type=mms&to=2065551212", url.QueryEscape(base64Attachment("../../test/testdata/test.jpg"))), + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedURN: "tel:+12065551234", + ExpectedAttachments: []string{"image/jpeg:EMBEDDED[17301].jpg"}, + }, { Label: "Status Valid", URL: statusURL, diff --git a/msg.go b/msg.go index 43c4e0104..c392213b6 100644 --- a/msg.go +++ b/msg.go @@ -120,7 +120,7 @@ type Msg interface { WithID(id MsgID) Msg WithUUID(uuid MsgUUID) Msg WithAttachment(url string) Msg - WithEmbeddedAttachment(contentType string, data []byte, ext string) Msg + WithEmbeddedAttachment(contentType string, data []byte, extension string) Msg WithURNAuth(auth string) Msg WithMetadata(metadata json.RawMessage) Msg WithFlow(flow *FlowReference) Msg diff --git a/test/msg.go b/test/msg.go index 799d0eaac..727450adc 100644 --- a/test/msg.go +++ b/test/msg.go @@ -2,18 +2,13 @@ package test import ( "encoding/json" + "fmt" "time" "github.com/nyaruka/courier" "github.com/nyaruka/gocommon/urns" ) -type mockEmbeddedAttachment struct { - contentType string - data []byte - ext string -} - type mockMsg struct { id courier.MsgID uuid courier.MsgUUID @@ -22,7 +17,6 @@ type mockMsg struct { urnAuth string text string attachments []string - embeddedAttachments []*mockEmbeddedAttachment externalID string contactName string highPriority bool @@ -99,8 +93,8 @@ func (m *mockMsg) WithAttachment(url string) courier.Msg { m.attachments = append(m.attachments, url) return m } -func (m *mockMsg) WithEmbeddedAttachment(contentType string, data []byte, ext string) courier.Msg { - m.embeddedAttachments = append(m.embeddedAttachments, &mockEmbeddedAttachment{contentType, data, ext}) +func (m *mockMsg) WithEmbeddedAttachment(contentType string, data []byte, extension string) courier.Msg { + m.attachments = append(m.attachments, fmt.Sprintf("%s:EMBEDDED[%d].%s", contentType, len(data), extension)) return m } diff --git a/test/testdata/test.jpg b/test/testdata/test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7d7d26673790c71998d204d4b6205a9daae3ce00 GIT binary patch literal 17301 zcmbTdbyOTd_bobv5Fj`S1RsJ1*TE$~@ZjzQcXtgQbdUhSgF6Hn+}+*X-3FIoczoZz z?|0XFf8F)Y^wgYHRefsh>8f76_vw0Bc-a78%ScE|01yxW0IAmx;AIo=N8H2G3;>Xm z1JDBi02IJGgm(bMR}TU3=C#26-~Q_f2t)v+|JDNl>IlUD^e|-eT*LJ|mDS$`O!rsN+*}~p|oP(Ja zz#}Rx_x3;0U+up>^?zOL8PcdlFrfPF;ZM{*C-P#+``hz*~Qh(-NVx>C^#fE>{ob1e8TUwUD~{hQ_9@?w;Ph{(-@vsp*;7x%q{~rOmDFo!!0tgTo`}<<<4g?cM#u<9~3y z{-6H~)@%8{ko|vf;k@E{^Y$&`Tjc-XLU`l;AK*A|kv_A%!xd3N{^9t6f;|A`qi9@q zRVOMXhw=rUk<;XRd@9aOYUqEU{TJE)9k9UvU&#Ik*#E(`3=n&rr2nxuuLt6rH?Nlp z@zvhGd;1@Ihy3ophWx(`<-dmdA4B^edwC6l@Sigg5s_XGG?aHJ|I_w=?YykMPD_lJ zB>+0&>w>^R!~qBc;9c4@QJal>rSbtkjhE^Q!)M!m1ZkZ#JZi{2r5`s2LM5K6bD8GX zs&+!9{)FMp*M8}KS0szSo){|5y@Ss){D-hnW|TElni#+Ow;4B|qrM>zj<;HLx)^r|BAJYm37MX&pK?CSYzC`O zG~)}97UGqZRPHehJ*GvMgvnKO%o(rnlRohrDy=N7X-iFx_b?AA^m#;GRUW8D}7BcEd1gL&Rn%u#nBP=G()40XP5zOAGWR-p}zink=zR6|vEV@;=VZ%#DOu zJJA;|@;vYqJKEY&!D5URQ+{=&8ljN3|U(u^e&tw?a4_!BxaUhg3qznTcPV& z;*vKuj5cmQbw4U`adB`6TyA*56}d-vKB32t?stKXa02M{(Surd(rvVVOw$p*ziCq8 zpyUKPFro^E=)`o#;$>d&w;P*KwUl)*htHokCU)E80Xa z!>YD}-C0?81=|q@k|rD&b}4V9a4KG1#I8>UCxbk-jK5d)&(#n*Pi2f*(teb6wiojw zxVzGRN279?K8Mu0_{-$>w$$imk22=BGi_Clg0ti)7H*QjRu);&y35tgUiH)g_i)rK zZ90QdjHyw~?-k0+78Rdf_@MRAV~p-}v^(jaODn2?jpV#U!?pUwsT(`)9{ARE1nl=l*3l9f9U7 zrOZ5)XW5eXQLPw3qqBs?rfd=TCI6J@je6oc-eY-{J*@bmG+r^1bg%b~_I9ef5;`C0 zqte=X+zqM32X@qL^V8jt z>r(c_5<|2)A2Efs10V8}#Oh2M=0-`mL=kqYx<=npo`@T0J@8PtpqC#zc0=8 zw}T1KGO9Tpqb3TkMeYHInr(&Q0y!@L7qxI>>0FCE;>1uC!OmknNwx=BPNi+~3ty`; zOH_k|bPee(JxpJqX3G@qTVl&hX8sT=#0R5)TVcZl>JtUB>x zJjfIfSl)8|O<_Mik4S=4g@n2eO2?XndLd5VCxY@X^E-njm*1Qd|F+4!H~UCC^~cuG zxG_{ti(aEBkCGFaUaGsLPIZTjJ}jwy{{=9wqk+w)mpfk%+*XATyZ~OSW<}y&rr=#W zb!h}jD%wmVxMx3NtzDWzy3kcLhL+rkPIWAtgo3NSlK{M?O~{;JB~~A5>hbJoqlNUX z;@hG~qWH_%0O)x;``2YA5&??@8h&b;>dd(o)m$22FB0snGef(mtQ2SY(BTn;KU>AJ z=*?HP0qPW~7Ji~mmQ)dpqc(4@G%snBmc8a$l0S!PZm3Dtt3L$n<)|-UYFjS~*J{X2 z8$F57WM^6Ph^y(E{z>0Je>Ax*0~5;Q6S&-Gm|9%z@xA%vdHmC}zreC-EZf$!3^k2y zkl;O)euEu~P)?moIll<>1B&?2!+1QR<8byfQ%s4p#ORqPr^&+RSg03h%wd7XbN! z{|a8VDx;>jRqeLP;Sl|ZZ;&=@w7{o6Qh9(hJ%#Opk?qLx%! zjsh+q^OFQq1UZ|muU&EgImmz(W>F^vGbPz^ni~Xn{QIlWcvWK=Uxbug{(bHXFXd(V z!};G|IO(bVvYiZX6%mB4aZcZNq0AV%{FNl+DU~D14dunt;5k4Mx;_zd5xpJKAy>7v z`)CrN9InaccZ0Svu#F_AU9gbxjrAikJ)8U*L}ZwIl?Oyd1An&qcLKIvd6|ay>6{{- z#arQ4D3H(2eb#Vx;8Ubx=bGR-PQ6i<%o;g$oYZLwh!MFhWzCCNfvV@e|Af{nPpGQK zz$Dc$Be0cE&RTNLVUG4wP!42<6ahKKoj zFI1v4B&~vHuXVc%PB$}}ACZ!V;UK*)u-9gI(aqXaZ8wPMm(!Znjjk-n1AaL1&#;#N z?i{hyKlez}=<19y-5mez2-)h!L$jvNYeVDby-Sd-M|W+|<9w@5tZv+@#)F2)DARD_ z<#_*nK3{L}FCGtFTs~O&>r$&MF5O>`iS3g};|D(+HC{i}&g~2v@5oLvi_pe6&#6-Ih#1*AR{ z#TR@5;6%75!2JgbN6EGvC0}OXU2FUIZhPety$JLis=@r8cviG*blbcY=a%Jhg98e; zVPZcK@H|Zc&Vyy1cF5`kC4mPC(e35TrncWs>iLAZ-tY*_yZ|gCNskkib<*PnkG#z- zsyRAy9xYH;PwY5HGa0y!g!$)rOAVUicnJ$oX52w+&CD|U!d&Tj+24HQCjJu;i=fP# zZAV*mi9R&enXoJ@b9h?udnwBIM1zG_lP#toM<;PyP$+SBG(T=6v0~8Pes{f|3QMLe zc|-%b{1bbJMnYD;dU&qu(mTgdT`Q_G*+^em2EO#5g{>5(A*5xk%kRcOimZH5X*>T6 z19mUGs#09S>eUdrThp6oYos$O@LA9^y>OlE;o}S7rbJoROvw0U7T%NNwjV15(SzUc z?}|yLW{h#@(Q~=4bV8~`4LOnyzegvABNmn7KA0!k?EMvAa0-f;6=xdr)Jwn~@IB(- zRS8lnbVsz?zA5Xm^m#77^Hz?>Z8~!2I&CBGFe)hX_7z3RU3e~OdAw;cw-A84+(^wz zYoDg=ydwbZtz+9zc{50pgU15b4rv-9;a(E0RqM#<>bV}7tMXI(LWx<$RH(u10TWU_fObn>i2kr7F)r76%LNIj^|Xd?8X5(I``*w#QT zs75GE(Dt^~>5=#wPiJD+PUcU{!i!2YDEJgDZ%Ld998AH@EfBz2q7D-JOQv&;mvMuf z(=348*W_CP-ikb>{~R2uj)Hp7`W40y>H5A0^Y`$oyv}lAQ*-i2l2~I3m?|@GR>=uv zMSfDuwgxjtdXJml(un;Fub>rv!|)GJvYhnl;$u0kkOSQ>sG}0y$Zv9SB{Ss&hGN`` zN8iie8E&tr0sg(+1_{TuuRYTzpmHQ~uCIHmPiFq~f0=`~*V_@NMQCm_b`YsvhKlVx zst)ZY+p)zkw7ss8Zi4!TzF*~{D72|DvVpnC4{9u+B8>yO+N6-kxW;~nneJ+tr?|lN zUBRjq3n3y&=1ua)Hj_+aTzPA5?>N7py`&>a5?D^PId1bMZ$YN4Dgl@JX?w!P`afNs#3miHWX606-7?aN##8nBHs}U|?X&%^@YHQ!S=HgGSNPY+bJBa%kAkJTPmh1TAS!R+#LG@uY z4KDzx*@fjYM7Z`FEI}?0=3EsH zl(&Je@yP;fxJ!aO~5tK&EXpmGERt9Fbs;)I28`tgC_UB0D|$+{#s~g z7t~YqFe^{fVYCh?HMVsBe3QPhPj;HXB_3 zP`$@-9}qXL&tNnVIdK<1RMUJyJ^fQ!B$MBHsa?+;9hYh2a|yvX`R`eW)0pDukvg#2

sDm5eS>OF z)16K&At@syJW7q{(#pVFg~7F#K|7HL88o%BlxGON!o)E3wEhpZS^u(dRW=fCoM8FZ zc&fA?Z@~tMr+i*97o@Ef#cSj6&RJ2rU4_OiMPiO$P7C4+AS$}U+{Y!EapK2E_f|0_ z&h&EGOCFOM3=tT(ltvaTF`#{}gB{|RfF@q%;oWOvY%@>={GcC8>)ck`J8iAe|K!<} zXdn(@ZX7oi1=sV&af7-CW)Q<3cf3SS#=OoD^t}6%9fc<0jPlFwSHp`7ZdKur}2Vr_VdzQO5HYqW@cs z5wtq^z(U^*wi;jfM0jX~y%cPRH|)Suk*itTIC1?ef3|P10#g*cDK;&%e_cxUNmdK= zWN^yJ`8COqXHY5bajU*Xx60~Dibie|uDk!YLO{$>o^|D@TT+ep#Ai5vNz!rKR>7d& z)b~3@dF}vj_&avW@l~OlDX}N@`>QTL-isGNpjmZ<6bN;47+8bOOrHJ^Ww_K)6or#e5Nn8L^_K8p8h6>?U$A$zm- zwZ(pOr|9B;f>2XI4|roTXND21JcKat>)ltO@R(1)j{s^PQx0MHK|j2E>_vK37%Kk` zFK>Zux#7h6^g+OS^I6`yoKiYaP^jxhi@5^#aN80wkkG&+5+ViofjZ{kvDfA}_X02z zUi8}I@OCvqd5TsFp$`7k;VpLb(5G zY9cAE4j+A#hR2oj-ud`y<&SpItv*#2ua9y#V62*J$r)&A0T_hqr*?jJ+POcQ8NbpquA9z2mU3s z@cI&}#CaeV&-iS@+PfEk+T;AbecuZp)ZOi$&Jm92h2G*yKc_G=82MinATo|-kLT7CDVlj_LY0~Nz$KqL3{dC(=ggHeNL}*MX90p2~;vWL4gudH*cEs zl%eVr$m{wyR|V~*k{>UB+{Q}_+*LByc_d9V9xDy()0Rc2jU)STN6#n}YO?C9{!w%v z7x0?u7Y;aC9Y4e-+QLjpJq+#nEv+jd{e@P=^$Ky6upza@973WTb zVUCtM*IW~S3+?aG(3ej)V$6+SAkiq%yjSNmjgj`*;6vZ^&+t?7(AgGv#4JfoCx|UZ zta!(9YM?9mq`ItUDav5+X6)-8hzk5;0;^n?Cnma_+U$FSQH~eae9E0Xc>5gP!|0Nf zRwb0d63d~HM`*7Vs17|3EVm`v%#ZHIlqGXKG>C+g-xqHQ;~inI=>LoQ`T#C)JoBD+ zExb=torN$E>nvxnTNfzd)_)}oG{O4nLDQJsGwp1})^uR25^799vsTy$pI9TmxVa5? zbTzh+cC2GWhmCg7E`vIJXrA=Ipo_(q!+M7}H`@)`7XDLo^bJ>5?(S+@* zM(gf%q9)EaeGJ+6w)P}^-;N2_)5561$XQqY5O1FEl8_!c*Q$-}i?d9O&by~^@z_wG z$&Zof-h&&wpIsgXm6lfShT7YepL#q^O{oD zy~(WQaqpBoZFulxu;Zi%qGA$DpDXQgP=@^JuUF2idNz%{mWFs(hv)I8y2w$lTq~GB z1WUrnH^LxBL?&bE?e6qOe*n~`MijDnIPiO2a_GI*m-p9l|aR77v1HAHN%-$(uQw6{o~I6b16QQw6B_l}AjwRg(UX{K7y5u5Cm@JVQg zu-PZHgu&rNW3WiT!@Lsbq}I|qDwly%{SQ#>%kAzLzz3JKVY6krDZ8eqK>RIcl)F(U zecJoz;-e*NvBEDgYAUVV#=>U_osYN-SB!VRE?jDe8tA8YQ)@I9S6!|ypTL!ykB;dS zc~ghG?aqbJ!X9E`@>{4B;!g?w`CcHdAJxj@T97;K?-N=2 z+w63JU1AQipz1$B&@y3VP#Y`EW2QwMTwNdkkrjS_-SIfzx2G$KQaIo@9q-_C#8X$1 zrE-vk=i^;dYp!hayHd0a0Bf2b0#Xl}C}zhUyS zNG}#ETc+CD`vNp6ftov2Dx{IV^P1lg4)amxti%@CCe^>aQvl0T zX@i25WCiMR-;{kC`#}^eDs48#&Ni-KI|V7K0O1s4nAunBcd#&>-B<)pbcw=s|lMATe*#A_674^*^=7{dB5h?CcL1l&W|e6_6J&V39|%y=!y#jQ^Yl$AeF2 z;ko{5QP>cCe`DzUHoVyC*W4|X*bR%g?;ow8dH?FN-f!t4i#XGS zy{k{9oEjy+*-MyewX!hrsWeOf;E`=^``;Wj*dmdD(d5#2-#8(o->C-Eb9p_%K&vn; ztD8t7tw2|7XY3a4lLBPBA~+pyn_!rMqryk{?7MrzbfM8p)_h%?@Nbu=M*eDI!z8a0 z*YO~y4E7_qKGLUi{sbCykN*N7dSoWrq9W6DyCEZ9bNN!jk^ z&09TUyPu}i7_@wcT0HCSY)}X!$$;R=e-gT(xeQwR>x8`(zs>T2;)e6&{r3q-Tz%Q3 zgP^#TZ^iLbKMW4))l%SN4OF^}30ALrOv5h$zG}%8k@T1GS!3xxISlVgm~ewaY$A-u zCLI&>=ni6}8OkwU0JYUWz77C~@^wP|n;++}XD~-Yyrz|XpXr>LL#X2UiYlqG!r5vX zK|esDYhMYkK_g`yy%0=sH4ILlD3!+a5}j{u=8B>EG(3andQ9aDD4%#qs}A+$sWZiz z>dGr<7c{v5*V)X0w`EW)uyZGEj~sUKZf)uMl!b6#8%xkuWeCV0U+}RarzaD;Lh{q|O9}Mw zOGO!N$%{MwK5e%(SA+^RjUm!1)SbHBFIM7>(hJfSvC0rt{{8mHKH| z(^*z~=?@nlZ{C+^>c~V(Pq&-R>$vzyw!Q$mQT;}jYLexIl^|5uT^KUTyw|w)Z;I<- zxZ}5WbAHAp9x>SKUG)zCfTD&pF|mY0?kJe>7);>M1kk)~AsJWC?P zD=fxq+8B9;V^ZLDR`=&kJ=)&MBO@I-D`SlC7;aD6-wYfSeeW)ZiguF;^$GjIpw1qXw_Mi`Y81G&swA(d3?~nQcU-<^R-@rUkY}+ggOu$z#UklM`4(Yg2U{i&w%~@pCws#R@NUZfM z&caBeTx^M*)(>iw37MpPJ!v)vR90_mw4f+`Njgp6vf1~t+7(${9Xhp*Jm51 z-ob`|GYZpqvv2RAef{z8UjW#;5ksCa{%TG~iIo=;!eIKt{i;Eg7-& zJD7s;z46l*_-H$d=_epY3u^YkCG_do`%B9jACN7G%lFDaPV&m9KOJ3TU%lo@&$^9b zBINw1OTj;gugtmvU&iD*3CnXfUi#2+h}?+Qh_{KMX#BD~$0MzMe1^y!DT74SWRzbc zZL_*lYq>qQ?KnPfi{lM7H8)qhZS%4BvPPxo+!m(w9!r$EyUIQI6gyC~CkWivmX3@} z(dKoZ#Rk?hV|f8E&hNsGZ-A)2Cs+PeEEC(K!atvtHV;3rhd2iE&*bz85pjT()Q8R< z!n_iO#dQZ94W{B{_D2QL3A3fCFBR5Ek1Q!QLkXZqmP8*OC z2hXf!UHK}w9O(XyGae@&(4*|RBLs~3T5SzbbPtGQ5-tDzQrOJ0xGb>GcC#O`q*Ton z-juqx1XrLP4h~3Ip2|Qv-TxynmRR@grVw8D<n5##n02cJqSMO%`H{(jF3yilFv~fQ~s?tVGV+Vo&T-?|mgyp2#z{NHeByE_C zEJL?x>Ds8F-|*f;!MzH?Ex9jfo9&cKZubpE zhMnriPL-$Gx6p*?d?z@~b1H^L*!uU2Yv>c0SO-(EJcFP7i87V5MjK6`aHApasDDkM^2&-Ooq5=JlMmt(EsS@< zem_!YRv1DtJH=A>0aCGVz$HW#>fjuM08I0H`yB7bzh>c7(VVZDp=c?D zUmtp;^SoTZY1ETXukYZLXeAkU2%Q66Vq`~ZL40Mwc+~fk z*&B?^42He-#j8z{EEG;X4S8S5(|xs>{h7sY`r2Rb5ZozDQx=^XkrvZv6AYxqVtq?H zRDvp*WnvuLqSwyPtF9MhoT5>hVil8B%T4cyKv#vmZ;^Yb?r;ikDsz7Cn9Pp|vCcDs z)<4P$B?`FXS7Ci=F?YD4q}DWF3_xDdIBCP`QyyEc%N#RE<#Co~F}6N-4j4G%n_=GU zwK&4Cr}EBLWINQ9r9F%K)yl7NJ(9f$>S5g&(EJ$8r^vLaQB)_B6Qrsze4AC z=mz&S61Hd+aqfH~$K)-+ISvVTeZO`iGpww8=6c})*8D_Fyr<727*Jkrpc1f5))DqA_`3J#b1A3xipB>n0MEwxwu-b+laFw_u9#meAE~QerTifK-<*i(pblK zm2zo-$Y#}uP@O{1^JNV)BUrI$BOZ0OR^a-Ln=P^2t(VT{@3RgKLWM7sTV;fCVGEUU*o*5_GkOVt0sFU(z`o^9!-<76f!0E+Tdw2g!)(Q3oKJSW0wto=Scr?oM7 z&`LB~%ZYUzdit6(enTYN7;g2Td^Ry{4oU@YCc{30``gg(g^ReO?LPDf(b|5MG^7zh zcU=56n<+hFXxDwF26*Frfm%5NZ9$Gn)SkI0myK77Xp1hUnm)A_bmc#UsuPN)mll$l zth=Pzg4PRCffIi5xg(1F^VJ@vk#U4PokzY58w!gmTa~@Q@HT(~2~2&$wuSpPO4{To z#E=`{*;yH1*tHl#(W)y%mL*UOQ@0x4_ZE(u4j*@Lp%aBzIu)O~oEJQ5!hg2#Xi8O) zttFl>5uJVwj=IBpsJSS;&3+YPV_ro{y4OT43x*cInEek|w_7ZVaAh6E<;$^{ zJ(zlmJGJw-4{Y^8g%Ht*oQk;~X17gN=Lh}Vg!9lyb1i^7bI37mbTFQKjoi9cC{U+n z()Qzrwlh<(8~+ztM&F;H`_(6WzqR&S$)3t3ZQ+1+qU$HBPmxXqJWQi4a~wK_DUg4c z$OIevu~NLJ2H5ba)bw>SI3G;oJ_~8U8;IVbr1Oq)uRg}4W+_E*ApScGO#NI=mneFm9{N)e`*GTQXN})Hj-$O6;kcw>11V{dI#%w5}R%g#+TNYx^Ks4 z+s)6zg-|cXz{W^p31uPeGt9b42`5J4QDt8Z5kuD-67Jl#(__qUeP(UXVMwGfT+gIC z4fh1m`_0XGcT@XpWDwLY&Ndf5tIu>#yg80H*l?teIqUMUDo@H>dpU`UTr4SWU#R_z zaqoSRbG(Vw)r!0cZ*?Z^%g$fOQyD~|;EJtbW5{&i2*{FoZtvD6_)f-5;8L#FrMqS+ zFY^LmpuUof4(;25E;KbHor}pEoYlW~svo=KCoaz;{nL3}hL)shJ2tyrfJEJT5ln2U zYkPb@TTH3bY_^)wFhJ36lX&htBSD>a8#loH=9S3T??i?m@*u}rf3AH%7fC8At9N_o zq+OW9^$ie|3rEi$ib6V35L1HRJq_yK>=ipuD-EjclNDscm(t)Ka7aQvYy?uN@|s&t zD0l)5a;pFtgW|COb0pkVghX_TTxaQS`K@gkRkrkq^%bm+Hx+hUPz{@r2E;aRjXVeL zVls&R2fKJh<4zbuVqCBzaRLVe_HEdXBlapMw~eUC@dU_nYNA(rG+llSoF0oMC4YX%jA-iJG#VN~ zmd9{u($B}~XiHAw0fJ?q_cw&;rhh)1>Zp4K;rHANc8sC+@-M3+vq6KOvwGm4{&0z{ z>3>5m<{IdI$@uB1XTYu!WdMt7&E96n)FOpL3M35cmD`1W;^B6b6v;XAikfh zIW9F6o-_PtVeg=o;n$<|WBWQ61?`*1Pbd%`96b}~9=`jtJv9Qk< zHN8vVZd;9QvM3qu5c^Z*BUDNXsl*wn8tjElk}s}5rW5+{9urCpd<-vu5iow!En6-3 z3=a7iVG1sYZJ=^R0?n<2g9CfRTer$$80j`ct3kIgx{I&h+PqR&KNmYq*>o4$clGhn z(|{{3_cth=+jyI*TQ=%M?@Obsc(pI(N{eV#r`4MyytQbp8OThkt?&vC>%UM>Uhi2l z2o2W005}5Y+im!fju=RPt@Cl-@}2KXSgGVF0K>X(r`8(}jY@jDYl}Jpjg-^qS?p z*d4Jf5z6v$xx7>Q2DEMA|Cy2-AumnOzVJ4EzRHKR<~bZjU8r@h(d~yyvT(rGz%QN>O=;HlKLpYQpgZy7lJZ#MH2meP}S@gk2t-C`e8F;`2%s;~+e z)Val$NDjsO`Xm;A`!UwT=nNuW000P~1amF%s)2&K4X!#R zX;;xLF%Sy6qV24^XfE%%uk8HRv@m&&C-f`l2*uLM`t>Sb2c8X#o4+ zeQSQ95U$g+gcSNWVGwVG+CVWS=khEuH;!uuBVY3;zvBv`!FM0NS6b`~?}uZj(oDCY z7Ji?IV$ch1vO`8@uhB?`x0`-s*s@j(QCPcd{ixBBn0Z?6a`2db)4{Z zuCJ-lVZJ+FfZ09=GqtGYz-;H?bUvhz8IT@v*CSWKId?4jwCBImKzynC$_&P3nZDq3 zX6qyWMRPbRc-uchn`u9y-2xSYg*MtyUS64ulexLdO}Il ze&V#-fs6>Jpvu`<$;qc#;=b?zOo>_pERLqhe0LY zpW9J>zvD{Ne~IaN{OUnf z|LHwl*6Z6EA?Wi-SNj&9Ls4%Y=a^2nR~YN$h=Pvz)gnhVQNN?cc3e2lFO`bB{Ax2f zPTz4nu%4dkPpu`NKFO`o_;aIFf55<^hNH{1_)dcFj_l^&W#PRSegH?prkfriV9+BJI@Xj5aR6vW^Isv%^i??bw}Tth;^0w<7rmeR%1IL-nlY zdAExkqx?Y5{r-520)$(oz6{#o%2P+wu`8dJcjI^c3_X_nb)g31eoT`YHe-PW6|2HS z%0iW&%ZXgf_O9Cxz>3WioVIqKV#U*s^<+E++h8`})a+iOLFvqTU)? ziENswY>7N$(ttR zh+}jiZD!(4XsnR!*;k%-twG&k)_udv59&%=B(5KG<*f@BV_KT^md=(L)`rDKdQAyr zim$r8Z+z{&t@F>zn~uENyJQu}v@Ot(d#sxoR%N{tn6uD2F}wVfswLy9kyV;AJ2Yle zfr@O=vztOdaz4ZTdAzg74`;F1&iw^!1|W5xX{Skpy2vxWzrU3uV6K8RtD-%uY=?SC z4JW+knp{2->{iJUE!LZrZ!Ce!ezcAFbIVHCFVUL9^*Y$4ZW1C^N*0k(Zk(iC}oAuH7=dtmH;ye4DkQ|)=A z_-lnxW%VrOd4AGS?e#J?_{vnhOs1mmu!i9uw|-=PN~NLt@=B9U)Pzq_Xi~mSHY|N* zuOxw!mTLZ(?VCEXSYOi4v2V}~^a>a?eejaJBfbRH`wO-P=5QS%#<)9Kb394PzW_3A z;r{O@74-s!R4G%5MR;7m!>^k%Q?v~11h1M$nBmJx-gPGl(ZhVdK2h^DYGahJ!1buJJQHPIlrd9~{(ZA?wl$ymFHq*iVWP~J&0^EA-L*s z>7a#D$>%F5b_>t7alA61Q#GjntuoYg793RYWR^t3#GK}tR2Q3h3{IsHUQ;Mm2i@=g z(lWKtr;q+F&}h}iy!t_7>G?)jelwFGl$)tson1yLY1}MzdRp~ndE)u>HDsrtMkiOD zdK+dVHx^kX>6PF}bYc`$gcCCQqGP)43UX0JTX(PUCm87#5Z9V0Byp|O8Z+aS!@f1b zaYiMO`h^t17q1G?wB?5zF>JL5v|p&P{A}Zn_##9r=De|7(@mVujqih=^a&>j;w#WA zW>74Q)%L}QZ_Hr8so!&NdwD`+NVovhRwea^iOqKh~)4YVE@G@Unv))$miMn) zZlN;UhvUiQo{{s|G56>_lc|oDKs&R_ZP=AVM0PzZ4L-upC65!28$AZGsS3ULqb05n zpQD2$Scg_)B*`C%7B8|ou|nP2sGFd?)1SRdmo02{c`$H$0fr@US&2MuZv*17KwEQt zyBxnWzH>w#S_-qsx(aXyk5I&ixXh=*v$n5*iI2sBXk?Z z&?Tw2*iL*wov+V$>K;F;KW4Vd`K)ea0L3RjjX@(4QfY5$i`C`UCbC3oo-TU3%j1QcW;G@PLgaObiAR0sZ5#Kr;gr33 zJOO26jOSYscd4qY-T018&21{f?Wik#OX!E&=zFvaqZ#2||4#>xm|J+1t<5pKdf=~B zXKOvT0HS;3*EfY>c>SBm!JA3*o0w^?Tf~6`zI8|3b^oGRpk(M3{88k{Byswo2xDL- zY0FvR%QNp3bCkWtX_tSRTJkIsrxviCQ@p#Z{52uyc$fWR&1S|O*vH!SU3j*o((cNQ znE;gquX)_yQUtp+Pi3SZk&k)S?eBZ{e3)5%EuXUWudDoG!*LRsld4ck^12Cb!)>bV z2)L85rF~TUCt-_99NI`YlSh)Cx~%fCwK2{mBYBK8poi;7CX_Ax+~|_T*bS56uJYD? zD(~L+!oOPxiwSaCd$0EULX34qgtQU#OubP@_Pa!*ukZBoa`n1dLH3bUz_%mo=uA(P zAf;HNm`T--pqDmh=@H^?H+Ke4O^|QNGO41k&T1W-qR+FUHcE;bx-b#2b6O88%KJC> zu?AIBNHvNq6v8yE@S8yj-Fyb9{rr?w{D59mJ~`Cy>cdP#@M$>8mFHL+f9W@VZ2fY# zDVW4d^^S;YVu+bhCL!HBwbbQO44A@q^6*b;9~fd$UKO06T`j1-$x^;~xv*(KJCB!9 z4Lonvc+%@_U0*U?7SI~T>vPn20c=uFzV3es@?RHzwpwBkqowv$c$s)EZ@AE9`Jnf; zPmvF3)fd^#9qB~l_tvkl!g`|2nWT3+!Q*^fW?57JyVR#jtJ`dOK`c6msd1kxDTU|n zWUzza&zlOG{q9o29_$mLV2zo|yfA}5`_spYD;{#0pD9C#!AhgJvL^5OfJ8F&bLhrw z8LicHR|@$G@0MQxv6*OehY$19?n3BCgJf5kp$)CZ9YlI7IxOT%3N9OS0^o+($t%u{h-y9Q|5Vq11bs5aq6Sh)27~NgJ+pL9$^P)SUTToZlblI z@KXxebN~f3%W5b`dF3!yulLB$^L~6Yro5oBxjNE^eCKo@{KFv0|CN$;XVu&%wn$nM zUY>nrrz2eGj^S9CzlP>`e2|^xd_cFV!EK~0z$yem_xoP;T~R2grLMXkvVuoQO4KIy zi(R<9>*7A{u@ccS*r{p0_@dbWjtU#;E!6(%*2LgGc&wtexU{f_q1*)u-9bm)BBn9O ziwpw>R5ruu;XUoxF1)Ev-51X}h)D?S4uTzn!0#G;kCj0_#(#BN>++2`?b1oIxA7jh z_-Xoo?5u2^UI~|0GcymeU2kpk6bs!7Ds-*aW}PB$cywG;Mnj%h^YGC889R(8&Do29 zBKp~;F90N*=Q@}COB*4o2bXmc7@FeP}$wGaL9{YKjHT5R1CEFV?R;?G`b@@Lwp zo$Y{AgK~qKEZBzxk&Dq4uNOe?=e?D0V!!?oy8Ayq&Q}F*!1T>I3nf?2sp00}Opow{ zo$I_+*H;yhQExr*H0L1&_^-aBlE_DK*5w5dzK&BqS|3(Bjiw{Q?5;11^1O`gxsahy ziT5;GU?p{l9~bBkS$F}2c=W{;=veUi@NxYTDAjRzBN2h3>+RaVttXzQr$Eu71Pk`* z^n7Nxg_CZ=gp@)wy>M=>%r9w)p@}|EL{QLm#1uo0!TxIIvpuVYkmTYzXvVVM9k&Np z3$2J$y+!9+Q*$-gX5U9^n|2TH;L&$%eNCG+!C{Pd2TSITsiMELsrVq~b)$`P10<1J z_f&ux6La%;DQ5$gbF&*@=FCkO&)>6!x*Szy#e!mt~I*Zp)M&VKsaJDz1j-Nf>Ilg}|( zE5flafcJHyzh0FR4Hi@W{PD%dN>bnB)_Nsd=7A;>*Zp#9 zqVni(UY6Jo`dU$R0(&+27l~yjS^+!Pcn7K4Wv_cn=P7S0V$k^AvxXhx8o)!f?V`U` z%wL6xE@Xhi=G#A~F_2-8w9N>sIEq)E;wXpbdTuk3HhX_Qe!zW%xBGY+`_ZU(zRQ zfUQLp&wjRcz>Z}kFD&!?{-Wy3)z`514l7=nkhRW2?Gwdr2O}pe-r`cxw8?TTNsQ>y zkNK#aejlt2F66*re3^ff@3eJsJBK(+ej;5D2wYmnM#53`F7%IXrD$rSHDfpEI+gjh zmk$kE`TD?x+Pb!Ztl7)R%Vde0WQ=uDN6}XKiJ!^;p8&@JIR35}j!q9e^X*(e*_cX> z@}|Dy)Q=KoG*zKmUwQd;;qUk*_rYx%{bs$={y_Z5!*b)>)9IS}m&0GNr^3$(z-NO< zvYlJzjg~RO_RksM*VVclB3Z_tJ2bGkB%__fBOHwM{3}mYi|oB(KKz*X||C-%g`c#IUfBg_xvMUqcO~z z3;yuetjnic8A6etFt9$@J*h1rTUk|OrYfZ0yw4&{COcb$ z5Ra3BGuIxU*0k-cVB8dg9H8VCI5p|lNfe5z@vqD|I* zJ6WybHrFyN#0=vZBp-iTZH>hCA2pn$fH_7O#a_}Q5ySRemO%SP?nnpHpCzmk%CShf zD7g*J;g9p)o6#Bi9f11<)ua+gf&8}&N$gEzYg%&KZPabmO3Hrl$6Bf3yZeiYB(ji= zk+4zfK|TF?*IB5?9GYWVF!={ed(mwZDYVtjMi)ulW}5}mk>42UT3^}^{zXu-v5q^o cM0X0P8yW6JYVAI!{QecBNlCuH*W7>q*)U2!3;+NC literal 0 HcmV?d00001 From 622a9763d2305eacd0d1e97c12254eaaac622b21 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 6 Sep 2022 12:18:07 -0500 Subject: [PATCH 134/294] Keep embedded attachments on msgs as data URIs --- backends/rapidpro/backend_test.go | 4 ++- backends/rapidpro/msg.go | 55 ++++++++++++++++++------------- handlers/test.go | 2 -- handlers/thinq/thinq.go | 8 +---- handlers/thinq/thinq_test.go | 9 ++--- msg.go | 1 - test/msg.go | 7 ---- 7 files changed, 39 insertions(+), 47 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index ca20bc8df..32f38ccac 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -2,6 +2,7 @@ package rapidpro import ( "context" + "encoding/base64" "encoding/json" "errors" "fmt" @@ -18,6 +19,7 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/queue" + "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/dbutil/assertdb" "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/storage" @@ -1071,7 +1073,7 @@ func (ts *BackendTestSuite) TestWriteAttachment() { // try embedded attachment msg = ts.b.NewIncomingMsg(knChannel, urn, "embedded attachment").(*DBMsg) - msg.WithEmbeddedAttachment("image/jpeg", []byte("jpegdata"), "jpg") + msg.WithAttachment(fmt.Sprintf("data:%s", base64.StdEncoding.EncodeToString(test.ReadFile("../../test/testdata/test.jpg")))) err = ts.b.WriteMsg(ctx, msg, clog) ts.NoError(err) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index 47c7e811a..cb26eaa2e 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -2,6 +2,7 @@ package rapidpro import ( "context" + "encoding/base64" "encoding/json" "fmt" "io/ioutil" @@ -60,23 +61,39 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch channel := m.Channel() // if we have attachment URLs, download them to our own storage - for i, attachment := range m.Attachments_ { - if strings.HasPrefix(attachment, "http") { - url, err := downloadAttachmentToStorage(ctx, b, channel, m.OrgID_, m.UUID_, attachment) + for i, attURL := range m.Attachments_ { + newURL := attURL + var err error + + if strings.HasPrefix(attURL, "http://") || strings.HasPrefix(attURL, "https://") { + newURL, err = downloadAttachmentToStorage(ctx, b, channel, m.OrgID_, m.UUID_, attURL) if err != nil { return err } - m.Attachments_[i] = url - } - } + } else if strings.HasPrefix(attURL, "data:") { + attData, err := base64.StdEncoding.DecodeString(attURL[5:]) + if err != nil { + clog.Error(errors.New("unable to decode attachment data")) + return errors.Wrap(err, "unable to decode attachment data") + } - // if we have embedded attachments, save them to our own storage and add URLs to the message - for _, ea := range m.embeddedAttachments { - url, err := saveAttachmentToStorage(ctx, b, m.OrgID_, m.UUID_, ea.contentType, ea.data, ea.extension) - if err != nil { - return err + var contentType, extension string + fileType, _ := filetype.Match(attData[:300]) + if fileType != filetype.Unknown { + contentType = fileType.MIME.Value + extension = fileType.Extension + } else { + contentType = "application/octet-stream" + extension = "bin" + } + + newURL, err = saveAttachmentToStorage(ctx, b, m.OrgID_, m.UUID_, contentType, attData, extension) + if err != nil { + return err + } } - m.Attachments_ = append(m.Attachments_, url) + + m.Attachments_[i] = newURL } // try to write it our db @@ -299,11 +316,11 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie return saveAttachmentToStorage(ctx, b, orgID, msgUUID, mimeType, body, extension) } -func saveAttachmentToStorage(ctx context.Context, b *backend, orgID OrgID, msgUUID courier.MsgUUID, contentType string, data []byte, ext string) (string, error) { +func saveAttachmentToStorage(ctx context.Context, b *backend, orgID OrgID, msgUUID courier.MsgUUID, contentType string, data []byte, extension string) (string, error) { // create our filename filename := msgUUID.String() - if ext != "" { - filename = fmt.Sprintf("%s.%s", msgUUID, ext) + if extension != "" { + filename = fmt.Sprintf("%s.%s", msgUUID, extension) } path := filepath.Join(b.config.S3AttachmentsPrefix, strconv.FormatInt(int64(orgID), 10), filename[:4], filename[4:8], filename) @@ -544,8 +561,6 @@ type DBMsg struct { workerToken queue.WorkerToken alreadyWritten bool quickReplies []string - - embeddedAttachments []*embeddedAttachment } func (m *DBMsg) ID() courier.MsgID { return m.ID_ } @@ -646,12 +661,6 @@ func (m *DBMsg) WithAttachment(url string) courier.Msg { return m } -// WithEmbeddedAttachment can be used to add an embedded attachment to a message -func (m *DBMsg) WithEmbeddedAttachment(contentType string, data []byte, extension string) courier.Msg { - m.embeddedAttachments = append(m.embeddedAttachments, &embeddedAttachment{contentType: contentType, data: data, extension: extension}) - return m -} - // WithURNAuth can be used to add a URN auth setting to a message func (m *DBMsg) WithURNAuth(auth string) courier.Msg { m.URNAuth_ = auth diff --git a/handlers/test.go b/handlers/test.go index f76db682c..d5f9c9d70 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -407,11 +407,9 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri require.Equal(tc.ExpectedMsgID, -1) } } - if len(tc.ExpectedAttachments) > 0 { require.Equal(tc.ExpectedAttachments, msg.Attachments()) } - if !tc.ExpectedDate.IsZero() { if msg != nil { require.Equal((tc.ExpectedDate).Local(), (*msg.ReceivedOn()).Local()) diff --git a/handlers/thinq/thinq.go b/handlers/thinq/thinq.go index 85a9d86da..e62dcc9e0 100644 --- a/handlers/thinq/thinq.go +++ b/handlers/thinq/thinq.go @@ -3,7 +3,6 @@ package thinq import ( "bytes" "context" - "encoding/base64" "encoding/json" "errors" "fmt" @@ -79,12 +78,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w if strings.HasPrefix(form.Message, "http://") || strings.HasPrefix(form.Message, "https://") { msg = h.Backend().NewIncomingMsg(channel, urn, "").WithAttachment(form.Message) } else { - imgData, err := base64.StdEncoding.DecodeString(form.Message) - if err != nil { - clog.Error(errors.New("unable to decode MMS data")) - return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, errors.New("unable to decode MMS data")) - } - msg = h.Backend().NewIncomingMsg(channel, urn, "").WithEmbeddedAttachment("image/jpeg", imgData, "jpg") + msg = h.Backend().NewIncomingMsg(channel, urn, "").WithAttachment("data:" + form.Message) } } else { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, fmt.Errorf("unknown message type: %s", form.Type)) diff --git a/handlers/thinq/thinq_test.go b/handlers/thinq/thinq_test.go index e14be7f0d..ea15b73dc 100644 --- a/handlers/thinq/thinq_test.go +++ b/handlers/thinq/thinq_test.go @@ -21,10 +21,7 @@ const ( statusURL = "/c/tq/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/" ) -func base64Attachment(path string) string { - data := test.ReadFile(path) - return base64.StdEncoding.EncodeToString(data) -} +var testJpgBase64 = base64.StdEncoding.EncodeToString(test.ReadFile("../../test/testdata/test.jpg")) var testCases = []ChannelHandleTestCase{ { @@ -55,11 +52,11 @@ var testCases = []ChannelHandleTestCase{ { Label: "Receive attachment as base64", URL: receiveURL, - Data: fmt.Sprintf("message=%s&from=2065551234&type=mms&to=2065551212", url.QueryEscape(base64Attachment("../../test/testdata/test.jpg"))), + Data: fmt.Sprintf("message=%s&from=2065551234&type=mms&to=2065551212", url.QueryEscape(testJpgBase64)), ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedURN: "tel:+12065551234", - ExpectedAttachments: []string{"image/jpeg:EMBEDDED[17301].jpg"}, + ExpectedAttachments: []string{"data:" + testJpgBase64}, }, { Label: "Status Valid", diff --git a/msg.go b/msg.go index c392213b6..c94dd6491 100644 --- a/msg.go +++ b/msg.go @@ -120,7 +120,6 @@ type Msg interface { WithID(id MsgID) Msg WithUUID(uuid MsgUUID) Msg WithAttachment(url string) Msg - WithEmbeddedAttachment(contentType string, data []byte, extension string) Msg WithURNAuth(auth string) Msg WithMetadata(metadata json.RawMessage) Msg WithFlow(flow *FlowReference) Msg diff --git a/test/msg.go b/test/msg.go index 727450adc..7ab7b76b7 100644 --- a/test/msg.go +++ b/test/msg.go @@ -2,7 +2,6 @@ package test import ( "encoding/json" - "fmt" "time" "github.com/nyaruka/courier" @@ -88,16 +87,10 @@ func (m *mockMsg) WithReceivedOn(date time.Time) courier.Msg { m.receivedOn = &d func (m *mockMsg) WithExternalID(id string) courier.Msg { m.externalID = id; return m } func (m *mockMsg) WithID(id courier.MsgID) courier.Msg { m.id = id; return m } func (m *mockMsg) WithUUID(uuid courier.MsgUUID) courier.Msg { m.uuid = uuid; return m } - func (m *mockMsg) WithAttachment(url string) courier.Msg { m.attachments = append(m.attachments, url) return m } -func (m *mockMsg) WithEmbeddedAttachment(contentType string, data []byte, extension string) courier.Msg { - m.attachments = append(m.attachments, fmt.Sprintf("%s:EMBEDDED[%d].%s", contentType, len(data), extension)) - return m -} - func (m *mockMsg) WithMetadata(metadata json.RawMessage) courier.Msg { m.metadata = metadata; return m } func (m *mockMsg) WithFlow(flow *courier.FlowReference) courier.Msg { m.flow = flow; return m } From 53e77e4170ab48e29a84326d973c41a8af6d49b0 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 6 Sep 2022 15:33:14 -0500 Subject: [PATCH 135/294] Remove unused struct --- backends/rapidpro/msg.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index cb26eaa2e..f0d89811d 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -508,12 +508,6 @@ func writeExternalIDSeen(b *backend, msg courier.Msg) { // Our implementation of Msg interface //----------------------------------------------------------------------------- -type embeddedAttachment struct { - contentType string - data []byte - extension string -} - // DBMsg is our base struct to represent msgs both in our JSON and db representations type DBMsg struct { OrgID_ OrgID `json:"org_id" db:"org_id"` From c690d0055ee0c207583295a17621b498d8c2e77c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 7 Sep 2022 09:08:31 -0500 Subject: [PATCH 136/294] Update CHANGELOG.md for v7.5.23 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 906788647..e47c4b334 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.23 +---------- + * Support channels receiving embedded attachments and use with thinq handler + v7.5.22 ---------- * Save channel logs with UUID From f9e5536202709cdb14fba3dc09ed52bb602b86d5 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 7 Sep 2022 10:53:59 -0500 Subject: [PATCH 137/294] Fix some linter warnings --- backends/rapidpro/backend_test.go | 11 +++++------ backends/rapidpro/msg.go | 4 ++-- handlers/external/external.go | 3 +-- handlers/freshchat/freshchat.go | 10 +++++----- handlers/jiochat/jiochat_test.go | 12 +++++------- handlers/line/line.go | 12 +++++------- handlers/viber/viber.go | 6 +++--- handlers/viber/viber_test.go | 6 +++--- handlers/vk/vk.go | 5 ++--- handlers/wechat/wechat.go | 2 +- handlers/wechat/wechat_test.go | 19 ++++++++----------- spool.go | 5 ++--- 12 files changed, 42 insertions(+), 53 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 32f38ccac..6a74149f6 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -6,7 +6,7 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" + "io" "log" "net/http" "net/http/httptest" @@ -17,6 +17,7 @@ import ( "testing" "time" + "github.com/gomodule/redigo/redis" "github.com/nyaruka/courier" "github.com/nyaruka/courier/queue" "github.com/nyaruka/courier/test" @@ -26,8 +27,6 @@ import ( "github.com/nyaruka/gocommon/urns" "github.com/nyaruka/null" "github.com/nyaruka/redisx/assertredis" - - "github.com/gomodule/redigo/redis" "github.com/sirupsen/logrus" "github.com/stretchr/testify/suite" ) @@ -49,7 +48,7 @@ func testConfig() *courier.Config { func (ts *BackendTestSuite) SetupSuite() { // turn off logging - logrus.SetOutput(ioutil.Discard) + logrus.SetOutput(io.Discard) b, err := courier.NewBackend(testConfig()) if err != nil { @@ -63,14 +62,14 @@ func (ts *BackendTestSuite) SetupSuite() { } // read our schema sql - sqlSchema, err := ioutil.ReadFile("schema.sql") + sqlSchema, err := os.ReadFile("schema.sql") if err != nil { panic(fmt.Errorf("Unable to read schema.sql: %s", err)) } ts.b.db.MustExec(string(sqlSchema)) // read our testdata sql - sql, err := ioutil.ReadFile("testdata.sql") + sql, err := os.ReadFile("testdata.sql") if err != nil { panic(fmt.Errorf("Unable to read testdata.sql: %s", err)) } diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index f0d89811d..c5fc54cd2 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -5,7 +5,7 @@ import ( "encoding/base64" "encoding/json" "fmt" - "io/ioutil" + "io" "log" "mime" "net/http" @@ -275,7 +275,7 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie return "", err } defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { return "", err } diff --git a/handlers/external/external.go b/handlers/external/external.go index f5e5b5014..959c6c998 100644 --- a/handlers/external/external.go +++ b/handlers/external/external.go @@ -7,7 +7,6 @@ import ( "encoding/xml" "fmt" "io" - "io/ioutil" "net/http" "net/url" "strings" @@ -152,7 +151,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w if fromXPath != "" && textXPath != "" { // we are reading from an XML body, pull out our fields - body, err := ioutil.ReadAll(io.LimitReader(r.Body, 100000)) + body, err := io.ReadAll(io.LimitReader(r.Body, 100000)) defer r.Body.Close() if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, fmt.Errorf("unable to read request body: %s", err)) diff --git a/handlers/freshchat/freshchat.go b/handlers/freshchat/freshchat.go index 0ba4ee032..d474a42f1 100644 --- a/handlers/freshchat/freshchat.go +++ b/handlers/freshchat/freshchat.go @@ -14,7 +14,7 @@ import ( "encoding/json" "encoding/pem" "fmt" - "io/ioutil" + "io" "net/http" "strings" "time" @@ -195,10 +195,10 @@ func (h *handler) validateSignature(c courier.Channel, r *http.Request) error { if actual == "" { return fmt.Errorf("missing request signature") } - buf, _ := ioutil.ReadAll(r.Body) - rdr1 := ioutil.NopCloser(bytes.NewBuffer(buf)) - rdr2 := ioutil.NopCloser(bytes.NewBuffer(buf)) - token, err := ioutil.ReadAll(rdr1) + buf, _ := io.ReadAll(r.Body) + rdr1 := io.NopCloser(bytes.NewBuffer(buf)) + rdr2 := io.NopCloser(bytes.NewBuffer(buf)) + token, err := io.ReadAll(rdr1) if err != nil { return fmt.Errorf("unable to read Body, %s", err.Error()) } diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index be641c606..79c8ecd79 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -5,7 +5,7 @@ import ( "crypto/sha1" "encoding/hex" "fmt" - "io/ioutil" + "io" "log" "net/http" "net/http/httptest" @@ -15,15 +15,13 @@ import ( "testing" "time" + "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/urns" "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" - - "github.com/nyaruka/courier" - . "github.com/nyaruka/courier/handlers" ) var testChannels = []courier.Channel{ @@ -247,8 +245,8 @@ func buildMockJCAPI(testCases []ChannelHandleTestCase) *httptest.Server { func newServer(backend courier.Backend) courier.Server { // for benchmarks, log to null logger := logrus.New() - logger.Out = ioutil.Discard - logrus.SetOutput(ioutil.Discard) + logger.Out = io.Discard + logrus.SetOutput(io.Discard) config := courier.NewConfig() config.DB = "postgres://courier:courier@localhost:5432/courier_test?sslmode=disable" config.Redis = "redis://localhost:6379/0" diff --git a/handlers/line/line.go b/handlers/line/line.go index 21bf6e23c..784328f4c 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -8,18 +8,16 @@ import ( "encoding/base64" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "time" "github.com/buger/jsonparser" - "github.com/pkg/errors" - - "github.com/nyaruka/gocommon/urns" - "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/urns" + "github.com/pkg/errors" ) var ( @@ -224,8 +222,8 @@ func (h *handler) validateSignature(channel courier.Channel, r *http.Request) er // see https://developers.line.me/en/docs/messaging-api/reference/#signature-validation func calculateSignature(secret string, r *http.Request) ([]byte, error) { defer r.Body.Close() - body, err := ioutil.ReadAll(r.Body) - r.Body = ioutil.NopCloser(bytes.NewBuffer(body)) + body, err := io.ReadAll(r.Body) + r.Body = io.NopCloser(bytes.NewBuffer(body)) if err != nil { return nil, err } diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index e4549b12c..b63a339f2 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -8,7 +8,7 @@ import ( "encoding/hex" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "strconv" "strings" @@ -273,12 +273,12 @@ func (h *handler) validateSignature(channel courier.Channel, r *http.Request) er } // read our body - body, err := ioutil.ReadAll(r.Body) + body, err := io.ReadAll(r.Body) if err != nil { return err } - r.Body = ioutil.NopCloser(bytes.NewBuffer(body)) + r.Body = io.NopCloser(bytes.NewBuffer(body)) expected := calculateSignature(authToken, body) // compare signatures in way that isn't sensitive to a timing attack diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index a9f2d72cf..fb41698d1 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -4,7 +4,7 @@ import ( "bytes" "crypto/hmac" "fmt" - "io/ioutil" + "io" "net/http" "net/http/httptest" "strings" @@ -529,8 +529,8 @@ var testWelcomeMessageCases = []ChannelHandleTestCase{ } func addValidSignature(r *http.Request) { - body, _ := ioutil.ReadAll(r.Body) - r.Body = ioutil.NopCloser(bytes.NewBuffer(body)) + body, _ := io.ReadAll(r.Body) + r.Body = io.NopCloser(bytes.NewBuffer(body)) sig := calculateSignature("Token", body) r.Header.Set(viberSignatureHeader, string(sig)) } diff --git a/handlers/vk/vk.go b/handlers/vk/vk.go index d80e666fb..72aec72d9 100644 --- a/handlers/vk/vk.go +++ b/handlers/vk/vk.go @@ -6,7 +6,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "mime/multipart" "net/http" "net/url" @@ -195,13 +194,13 @@ type mediaUploadInfoPayload struct { // receiveEvent handles request event type func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { // read request body - bodyBytes, err := ioutil.ReadAll(io.LimitReader(r.Body, 100000)) + bodyBytes, err := io.ReadAll(io.LimitReader(r.Body, 100000)) if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, fmt.Errorf("unable to read request body: %s", err)) } // restore body to its original value - r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) + r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) payload := &moPayload{} if err := json.Unmarshal(bodyBytes, payload); err != nil { diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index 8e8af96c6..2e094f2e3 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -69,7 +69,7 @@ func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http } dictOrder := []string{channel.StringConfigForKey(courier.ConfigSecret, ""), form.Timestamp, form.Nonce} - sort.Sort(sort.StringSlice(dictOrder)) + sort.Strings(dictOrder) combinedParams := strings.Join(dictOrder, "") diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index 46fba5537..716157777 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -5,7 +5,7 @@ import ( "crypto/sha1" "encoding/hex" "fmt" - "io/ioutil" + "io" "log" "net/http" "net/http/httptest" @@ -15,15 +15,12 @@ import ( "testing" "time" - "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier" + . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/urns" "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" - - "github.com/nyaruka/courier" - . "github.com/nyaruka/courier/handlers" ) var testChannels = []courier.Channel{ @@ -216,7 +213,7 @@ func buildMockWCAPI(testCases []ChannelHandleTestCase) *httptest.Server { defer r.Body.Close() if accessToken != "ACCESS_TOKEN" { - http.Error(w, "invalid file", 403) + http.Error(w, "invalid file", http.StatusForbidden) return } @@ -243,8 +240,8 @@ func buildMockWCAPI(testCases []ChannelHandleTestCase) *httptest.Server { func newServer(backend courier.Backend) courier.Server { // for benchmarks, log to null logger := logrus.New() - logger.Out = ioutil.Discard - logrus.SetOutput(ioutil.Discard) + logger.Out = io.Discard + logrus.SetOutput(io.Discard) config := courier.NewConfig() config.DB = "postgres://courier:courier@localhost:5432/courier_test?sslmode=disable" config.Redis = "redis://localhost:6379/0" @@ -266,7 +263,7 @@ func TestDescribe(t *testing.T) { conn.Close() s := newServer(mb) - handler := &handler{handlers.NewBaseHandler(courier.ChannelType("WC"), "WeChat")} + handler := &handler{NewBaseHandler(courier.ChannelType("WC"), "WeChat")} handler.Initialize(s) clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0]) @@ -295,7 +292,7 @@ func TestBuildMediaRequest(t *testing.T) { conn.Close() s := newServer(mb) - handler := &handler{handlers.NewBaseHandler(courier.ChannelType("WC"), "WeChat")} + handler := &handler{NewBaseHandler(courier.ChannelType("WC"), "WeChat")} handler.Initialize(s) tcs := []struct { diff --git a/spool.go b/spool.go index edacc9da6..00fbe6ead 100644 --- a/spool.go +++ b/spool.go @@ -4,7 +4,6 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" "os" "path" "path/filepath" @@ -31,7 +30,7 @@ func WriteToSpool(spoolDir string, subdir string, contents interface{}) error { } filename := path.Join(spoolDir, subdir, fmt.Sprintf("%d.json", time.Now().UnixNano())) - return ioutil.WriteFile(filename, contentBytes, 0640) + return os.WriteFile(filename, contentBytes, 0640) } // starts our spool flusher, which every 30 seconds tries to write our pending msgs and statuses @@ -103,7 +102,7 @@ func newSpoolFlusher(s Server, dir string, flusherFunc FlusherFunc) *flusher { log := logrus.WithField("comp", "spool").WithField("filename", filename) // otherwise, read our msg json - contents, err := ioutil.ReadFile(filename) + contents, err := os.ReadFile(filename) if err != nil { log.WithError(err).Error("reading spool file") return nil From f3820887cdd89e8781d5e968e8d9a7fac1ca867a Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 7 Sep 2022 11:03:29 -0500 Subject: [PATCH 138/294] Use go 1.19 --- .github/workflows/ci.yml | 2 +- go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e2b6dd812..c258736d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,7 @@ name: CI on: [push, pull_request] env: - go-version: "1.18.x" + go-version: "1.19.x" redis-version: "5.0.6" jobs: test: diff --git a/go.mod b/go.mod index 2b2eb7f52..ee0a51f73 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/nyaruka/courier -go 1.18 +go 1.19 require ( github.com/antchfx/xmlquery v1.3.12 From 3d37146601e3aa5a5ea053ffe4d5fdce611da41e Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 7 Sep 2022 12:30:27 -0500 Subject: [PATCH 139/294] Set log UUID on incoming messages and channel events --- backend.go | 4 +-- backends/rapidpro/backend.go | 10 +++--- backends/rapidpro/backend_test.go | 40 +++++++++++----------- backends/rapidpro/channel_event.go | 41 +++++++++-------------- backends/rapidpro/msg.go | 40 ++++++++++++---------- backends/rapidpro/schema.sql | 6 ++-- handler_test.go | 2 +- handlers/africastalking/africastalking.go | 2 +- handlers/blackmyna/blackmyna.go | 2 +- handlers/bongolive/bongolive.go | 2 +- handlers/chikka/chikka.go | 2 +- handlers/clickatell/clickatell.go | 2 +- handlers/clickmobile/clickmobile.go | 2 +- handlers/dart/dart.go | 2 +- handlers/discord/discord.go | 2 +- handlers/dmark/dmark.go | 2 +- handlers/external/external.go | 4 +-- handlers/facebook/facebook.go | 8 ++--- handlers/facebookapp/facebookapp.go | 10 +++--- handlers/firebase/firebase.go | 2 +- handlers/freshchat/freshchat.go | 2 +- handlers/generic.go | 2 +- handlers/globe/globe.go | 2 +- handlers/highconnection/highconnection.go | 2 +- handlers/hormuud/hormuud.go | 2 +- handlers/i2sms/i2sms.go | 2 +- handlers/infobip/infobip.go | 2 +- handlers/jasmin/jasmin.go | 2 +- handlers/jiochat/jiochat.go | 4 +-- handlers/junebug/junebug.go | 2 +- handlers/kaleyra/kaleyra.go | 2 +- handlers/kannel/kannel.go | 2 +- handlers/line/line.go | 2 +- handlers/m3tech/m3tech.go | 2 +- handlers/macrokiosk/macrokiosk.go | 2 +- handlers/mblox/mblox.go | 2 +- handlers/mtarget/mtarget.go | 4 +-- handlers/nexmo/nexmo.go | 2 +- handlers/novo/novo.go | 2 +- handlers/playmobile/playmobile.go | 2 +- handlers/plivo/plivo.go | 2 +- handlers/rocketchat/rocketchat.go | 2 +- handlers/shaqodoon/shaqodoon.go | 2 +- handlers/slack/slack.go | 2 +- handlers/smscentral/smscentral.go | 2 +- handlers/start/start.go | 2 +- handlers/telegram/telegram.go | 14 ++++---- handlers/telesom/telesom.go | 2 +- handlers/thinq/thinq.go | 6 ++-- handlers/twiml/twiml.go | 6 ++-- handlers/twitter/twitter.go | 2 +- handlers/viber/viber.go | 8 ++--- handlers/vk/vk.go | 2 +- handlers/wavy/wavy.go | 2 +- handlers/wechat/wechat.go | 4 +-- handlers/whatsapp/whatsapp.go | 2 +- handlers/yo/yo.go | 4 +-- handlers/zenvia/zenvia.go | 2 +- handlers/zenviaold/zenviaold.go | 2 +- test/backend.go | 4 +-- 60 files changed, 150 insertions(+), 151 deletions(-) diff --git a/backend.go b/backend.go index 5e33e255d..f35b98ed2 100644 --- a/backend.go +++ b/backend.go @@ -42,7 +42,7 @@ type Backend interface { DeleteMsgWithExternalID(ctx context.Context, channel Channel, externalID string) error // NewIncomingMsg creates a new message from the given params - NewIncomingMsg(channel Channel, urn urns.URN, text string) Msg + NewIncomingMsg(Channel, urns.URN, string, *ChannelLog) Msg // WriteMsg writes the passed in message to our backend WriteMsg(context.Context, Msg, *ChannelLog) error @@ -57,7 +57,7 @@ type Backend interface { WriteMsgStatus(context.Context, MsgStatus) error // NewChannelEvent creates a new channel event for the given channel and event type - NewChannelEvent(Channel, ChannelEventType, urns.URN) ChannelEvent + NewChannelEvent(Channel, ChannelEventType, urns.URN, *ChannelLog) ChannelEvent // WriteChannelEvent writes the passed in channel even returning any error WriteChannelEvent(context.Context, ChannelEvent, *ChannelLog) error diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 46dea60e3..d61cf3b3d 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -131,12 +131,12 @@ func (b *backend) DeleteMsgWithExternalID(ctx context.Context, channel courier.C } // NewIncomingMsg creates a new message from the given params -func (b *backend) NewIncomingMsg(channel courier.Channel, urn urns.URN, text string) courier.Msg { +func (b *backend) NewIncomingMsg(channel courier.Channel, urn urns.URN, text string, clog *courier.ChannelLog) courier.Msg { // remove any control characters text = utils.CleanString(text) // create our msg - msg := newMsg(MsgIncoming, channel, urn, text) + msg := newMsg(MsgIncoming, channel, urn, text, clog) // set received on to now msg.WithReceivedOn(time.Now().UTC()) @@ -153,7 +153,7 @@ func (b *backend) NewIncomingMsg(channel courier.Channel, urn urns.URN, text str // NewOutgoingMsg creates a new outgoing message from the given params func (b *backend) NewOutgoingMsg(channel courier.Channel, urn urns.URN, text string) courier.Msg { - return newMsg(MsgOutgoing, channel, urn, text) + return newMsg(MsgOutgoing, channel, urn, text, nil) } // PopNextOutgoingMsg pops the next message that needs to be sent @@ -367,8 +367,8 @@ func (b *backend) updateContactURN(ctx context.Context, status courier.MsgStatus } // NewChannelEvent creates a new channel event with the passed in parameters -func (b *backend) NewChannelEvent(channel courier.Channel, eventType courier.ChannelEventType, urn urns.URN) courier.ChannelEvent { - return newChannelEvent(channel, eventType, urn) +func (b *backend) NewChannelEvent(channel courier.Channel, eventType courier.ChannelEventType, urn urns.URN, clog *courier.ChannelLog) courier.ChannelEvent { + return newChannelEvent(channel, eventType, urn, clog) } // WriteChannelEvent writes the passed in channel even returning any error diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 6a74149f6..1061ad724 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -749,7 +749,7 @@ func (ts *BackendTestSuite) TestDupes() { clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) urn, _ := urns.NewTelURNForCountry("12065551215", knChannel.Country()) - msg := ts.b.NewIncomingMsg(knChannel, urn, "ping").(*DBMsg) + msg := ts.b.NewIncomingMsg(knChannel, urn, "ping", clog).(*DBMsg) err := ts.b.WriteMsg(ctx, msg, clog) ts.NoError(err) @@ -757,14 +757,14 @@ func (ts *BackendTestSuite) TestDupes() { uuid1 := msg.UUID().String() // trying again should lead to same UUID - msg = ts.b.NewIncomingMsg(knChannel, urn, "ping").(*DBMsg) + msg = ts.b.NewIncomingMsg(knChannel, urn, "ping", clog).(*DBMsg) err = ts.b.WriteMsg(ctx, msg, clog) ts.NoError(err) ts.Equal(uuid1, msg.UUID().String()) // different message should change that - msg = ts.b.NewIncomingMsg(knChannel, urn, "test").(*DBMsg) + msg = ts.b.NewIncomingMsg(knChannel, urn, "test", clog).(*DBMsg) err = ts.b.WriteMsg(ctx, msg, clog) ts.NoError(err) @@ -787,7 +787,7 @@ func (ts *BackendTestSuite) TestDupes() { _, err = ts.b.PopNextOutgoingMsg(ctx) ts.NoError(err) - msg = ts.b.NewIncomingMsg(knChannel, urn, "test").(*DBMsg) + msg = ts.b.NewIncomingMsg(knChannel, urn, "test", clog).(*DBMsg) err = ts.b.WriteMsg(ctx, msg, clog) ts.NoError(err) @@ -801,7 +801,7 @@ func (ts *BackendTestSuite) TestExternalIDDupes() { knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") urn, _ := urns.NewTelURNForCountry("12065551215", knChannel.Country()) - msg := newMsg(MsgIncoming, knChannel, urn, "ping") + msg := newMsg(MsgIncoming, knChannel, urn, "ping", nil) var checkedMsg = ts.b.CheckExternalIDSeen(msg) m := checkedMsg.(*DBMsg) @@ -1023,7 +1023,7 @@ func (ts *BackendTestSuite) TestWriteAttachment() { knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) urn, _ := urns.NewTelURNForCountry("12065551215", knChannel.Country()) - msg := ts.b.NewIncomingMsg(knChannel, urn, "invalid attachment").(*DBMsg) + msg := ts.b.NewIncomingMsg(knChannel, urn, "invalid attachment", clog).(*DBMsg) msg.WithAttachment(testServer.URL) // should just end up being text/plain @@ -1032,7 +1032,7 @@ func (ts *BackendTestSuite) TestWriteAttachment() { ts.True(strings.HasPrefix(msg.Attachments()[0], "text/plain")) // use an extension for our attachment instead - msg = ts.b.NewIncomingMsg(knChannel, urn, "jpg attachment").(*DBMsg) + msg = ts.b.NewIncomingMsg(knChannel, urn, "jpg attachment", clog).(*DBMsg) msg.WithAttachment(testServer.URL + "/test.jpg") err = ts.b.WriteMsg(ctx, msg, clog) @@ -1041,7 +1041,7 @@ func (ts *BackendTestSuite) TestWriteAttachment() { ts.True(strings.HasSuffix(msg.Attachments()[0], ".jpg")) // ok, now derive it from magic bytes - msg = ts.b.NewIncomingMsg(knChannel, urn, "gif attachment").(*DBMsg) + msg = ts.b.NewIncomingMsg(knChannel, urn, "gif attachment", clog).(*DBMsg) msg.WithAttachment(testServer.URL + "/giffy") err = ts.b.WriteMsg(ctx, msg, clog) @@ -1052,7 +1052,7 @@ func (ts *BackendTestSuite) TestWriteAttachment() { } // finally from our header - msg = ts.b.NewIncomingMsg(knChannel, urn, "png attachment").(*DBMsg) + msg = ts.b.NewIncomingMsg(knChannel, urn, "png attachment", clog).(*DBMsg) msg.WithAttachment(testServer.URL + "/header") err = ts.b.WriteMsg(ctx, msg, clog) @@ -1071,7 +1071,7 @@ func (ts *BackendTestSuite) TestWriteAttachment() { } // try embedded attachment - msg = ts.b.NewIncomingMsg(knChannel, urn, "embedded attachment").(*DBMsg) + msg = ts.b.NewIncomingMsg(knChannel, urn, "embedded attachment", clog).(*DBMsg) msg.WithAttachment(fmt.Sprintf("data:%s", base64.StdEncoding.EncodeToString(test.ReadFile("../../test/testdata/test.jpg")))) err = ts.b.WriteMsg(ctx, msg, clog) @@ -1093,7 +1093,7 @@ func (ts *BackendTestSuite) TestWriteMsg() { // create a new courier msg urn, _ := urns.NewTelURNForCountry("12065551212", knChannel.Country()) - msg := ts.b.NewIncomingMsg(knChannel, urn, "test123").WithExternalID("ext123").WithReceivedOn(now).WithContactName("test contact").(*DBMsg) + msg := ts.b.NewIncomingMsg(knChannel, urn, "test123", clog).WithExternalID("ext123").WithReceivedOn(now).WithContactName("test contact").(*DBMsg) // try to write it to our db err := ts.b.WriteMsg(ctx, msg, clog) @@ -1101,7 +1101,7 @@ func (ts *BackendTestSuite) TestWriteMsg() { // creating the incoming msg again should give us the same UUID and have the msg set as not to write time.Sleep(1 * time.Second) - msg2 := ts.b.NewIncomingMsg(knChannel, urn, "test123").(*DBMsg) + msg2 := ts.b.NewIncomingMsg(knChannel, urn, "test123", clog).(*DBMsg) ts.Equal(msg2.UUID(), msg.UUID()) ts.True(msg2.alreadyWritten) @@ -1149,17 +1149,17 @@ func (ts *BackendTestSuite) TestWriteMsg() { // waiting 5 seconds should let us write it successfully time.Sleep(5 * time.Second) - msg3 := ts.b.NewIncomingMsg(knChannel, urn, "test123").(*DBMsg) + msg3 := ts.b.NewIncomingMsg(knChannel, urn, "test123", clog).(*DBMsg) ts.NotEqual(msg3.UUID(), msg.UUID()) // msg with null bytes in it, that's fine for a request body - msg = ts.b.NewIncomingMsg(knChannel, urn, "test456\x00456").WithExternalID("ext456").(*DBMsg) + msg = ts.b.NewIncomingMsg(knChannel, urn, "test456\x00456", clog).WithExternalID("ext456").(*DBMsg) err = writeMsgToDB(ctx, ts.b, msg, clog) ts.NoError(err) // more null bytes text, _ := url.PathUnescape("%1C%00%00%00%00%00%07%E0%00") - msg = ts.b.NewIncomingMsg(knChannel, urn, text).(*DBMsg) + msg = ts.b.NewIncomingMsg(knChannel, urn, text, clog).(*DBMsg) err = writeMsgToDB(ctx, ts.b, msg, clog) ts.NoError(err) @@ -1168,7 +1168,7 @@ func (ts *BackendTestSuite) TestWriteMsg() { defer rc.Close() rc.Do("DEL", "handler:1", "handler:active", fmt.Sprintf("c:1:%d", msg.ContactID_)) - msg = ts.b.NewIncomingMsg(knChannel, urn, "hello 1 2 3").(*DBMsg) + msg = ts.b.NewIncomingMsg(knChannel, urn, "hello 1 2 3", clog).(*DBMsg) err = writeMsgToDB(ctx, ts.b, msg, clog) ts.NoError(err) @@ -1216,7 +1216,7 @@ func (ts *BackendTestSuite) TestPreferredChannelCheckRole() { now := time.Now().Round(time.Microsecond).In(time.UTC) urn, _ := urns.NewTelURNForCountry("12065552020", exChannel.Country()) - msg := ts.b.NewIncomingMsg(exChannel, urn, "test123").WithExternalID("ext123").WithReceivedOn(now).WithContactName("test contact").(*DBMsg) + msg := ts.b.NewIncomingMsg(exChannel, urn, "test123", clog).WithExternalID("ext123").WithReceivedOn(now).WithContactName("test contact").(*DBMsg) // try to write it to our db err := ts.b.WriteMsg(ctx, msg, clog) @@ -1245,7 +1245,7 @@ func (ts *BackendTestSuite) TestChannelEvent() { clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) urn, _ := urns.NewTelURNForCountry("12065551616", channel.Country()) - event := ts.b.NewChannelEvent(channel, courier.Referral, urn).WithExtra(map[string]interface{}{"ref_id": "12345"}).WithContactName("kermit frog") + event := ts.b.NewChannelEvent(channel, courier.Referral, urn, clog).WithExtra(map[string]interface{}{"ref_id": "12345"}).WithContactName("kermit frog") err := ts.b.WriteChannelEvent(ctx, event, clog) ts.NoError(err) @@ -1287,7 +1287,7 @@ func (ts *BackendTestSuite) TestMailroomEvents() { clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) urn, _ := urns.NewTelURNForCountry("12065551616", channel.Country()) - event := ts.b.NewChannelEvent(channel, courier.Referral, urn).WithExtra(map[string]interface{}{"ref_id": "12345"}). + event := ts.b.NewChannelEvent(channel, courier.Referral, urn, clog).WithExtra(map[string]interface{}{"ref_id": "12345"}). WithContactName("kermit frog"). WithOccurredOn(time.Date(2020, 8, 5, 13, 30, 0, 123456789, time.UTC)) err := ts.b.WriteChannelEvent(ctx, event, clog) @@ -1464,7 +1464,7 @@ func readMsgFromDB(b *backend, id courier.MsgID) *DBMsg { m := &DBMsg{ ID_: id, } - err := b.db.Get(m, selectMsgSQL, id) + err := b.db.Get(m, sqlSelectMsg, id) if err != nil { panic(err) } diff --git a/backends/rapidpro/channel_event.go b/backends/rapidpro/channel_event.go index 886718fde..3014a5e18 100644 --- a/backends/rapidpro/channel_event.go +++ b/backends/rapidpro/channel_event.go @@ -10,10 +10,10 @@ import ( "strconv" "time" - "github.com/nyaruka/null" - + "github.com/lib/pq" "github.com/nyaruka/courier" "github.com/nyaruka/gocommon/urns" + "github.com/nyaruka/null" "github.com/sirupsen/logrus" ) @@ -51,7 +51,7 @@ func (i ChannelEventID) String() string { } // newChannelEvent creates a new channel event -func newChannelEvent(channel courier.Channel, eventType courier.ChannelEventType, urn urns.URN) *DBChannelEvent { +func newChannelEvent(channel courier.Channel, eventType courier.ChannelEventType, urn urns.URN, clog *courier.ChannelLog) *DBChannelEvent { dbChannel := channel.(*DBChannel) now := time.Now().In(time.UTC) @@ -63,6 +63,7 @@ func newChannelEvent(channel courier.Channel, eventType courier.ChannelEventType EventType_: eventType, OccurredOn_: now, CreatedOn_: now, + LogUUIDs: []string{string(clog.UUID())}, channel: dbChannel, } @@ -86,12 +87,11 @@ func writeChannelEvent(ctx context.Context, b *backend, event courier.ChannelEve return err } -const insertChannelEventSQL = ` +const sqlInsertChannelEvent = ` INSERT INTO - channels_channelevent("org_id", "channel_id", "contact_id", "contact_urn_id", "event_type", "extra", "occurred_on", "created_on") - VALUES(:org_id, :channel_id, :contact_id, :contact_urn_id, :event_type, :extra, :occurred_on, :created_on) -RETURNING id -` + channels_channelevent( org_id, channel_id, contact_id, contact_urn_id, event_type, extra, occurred_on, created_on, log_uuids) + VALUES(:org_id, :channel_id, :contact_id, :contact_urn_id, :event_type, :extra, :occurred_on, :created_on, :log_uuids) +RETURNING id` // writeChannelEventToDB writes the passed in msg status to our db func writeChannelEventToDB(ctx context.Context, b *backend, e *DBChannelEvent, clog *courier.ChannelLog) error { @@ -101,10 +101,11 @@ func writeChannelEventToDB(ctx context.Context, b *backend, e *DBChannelEvent, c return err } + // set our contact and urn id e.ContactID_ = contact.ID_ e.ContactURNID_ = contact.URNID_ - rows, err := b.db.NamedQueryContext(ctx, insertChannelEventSQL, e) + rows, err := b.db.NamedQueryContext(ctx, sqlInsertChannelEvent, e) if err != nil { return err } @@ -155,27 +156,16 @@ func (b *backend) flushChannelEventFile(filename string, contents []byte) error return writeChannelEventToDB(ctx, b, event, clog) } -const selectEventSQL = ` -SELECT - org_id, - channel_id, - contact_id, - contact_urn_id, - event_type, - extra, - occurred_on, - created_on -FROM - channels_channelevent -WHERE - id = $1 -` +const sqlSelectEvent = ` +SELECT org_id, channel_id, contact_id, contact_urn_id, event_type, extra, occurred_on, created_on, log_uuids + FROM channels_channelevent + WHERE id = $1` func readChannelEventFromDB(b *backend, id ChannelEventID) (*DBChannelEvent, error) { e := &DBChannelEvent{ ID_: id, } - err := b.db.Get(e, selectEventSQL, id) + err := b.db.Get(e, sqlSelectEvent, id) return e, err } @@ -194,6 +184,7 @@ type DBChannelEvent struct { Extra_ null.Map `json:"extra" db:"extra"` OccurredOn_ time.Time `json:"occurred_on" db:"occurred_on"` CreatedOn_ time.Time `json:"created_on" db:"created_on"` + LogUUIDs pq.StringArray `json:"log_uuids" db:"log_uuids"` ContactName_ string `json:"contact_name"` ContactID_ ContactID `json:"-" db:"contact_id"` diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index c5fc54cd2..5661bc18e 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -114,10 +114,15 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch } // newMsg creates a new DBMsg object with the passed in parameters -func newMsg(direction MsgDirection, channel courier.Channel, urn urns.URN, text string) *DBMsg { +func newMsg(direction MsgDirection, channel courier.Channel, urn urns.URN, text string, clog *courier.ChannelLog) *DBMsg { now := time.Now() dbChannel := channel.(*DBChannel) + var logUUIDs []string + if clog != nil { + logUUIDs = []string{string(clog.UUID())} + } + return &DBMsg{ OrgID_: dbChannel.OrgID(), UUID_: courier.NewMsgUUID(), @@ -137,6 +142,7 @@ func newMsg(direction MsgDirection, channel courier.Channel, urn urns.URN, text CreatedOn_: now, ModifiedOn_: now, QueuedOn_: now, + LogUUIDs: logUUIDs, channel: dbChannel, workerToken: "", @@ -144,14 +150,13 @@ func newMsg(direction MsgDirection, channel courier.Channel, urn urns.URN, text } } -const insertMsgSQL = ` +const sqlInsertMsg = ` INSERT INTO msgs_msg(org_id, uuid, direction, text, attachments, msg_count, error_count, high_priority, status, - visibility, external_id, channel_id, contact_id, contact_urn_id, created_on, modified_on, next_attempt, queued_on, sent_on) + visibility, external_id, channel_id, contact_id, contact_urn_id, created_on, modified_on, next_attempt, queued_on, sent_on, log_uuids) VALUES(:org_id, :uuid, :direction, :text, :attachments, :msg_count, :error_count, :high_priority, :status, - :visibility, :external_id, :channel_id, :contact_id, :contact_urn_id, :created_on, :modified_on, :next_attempt, :queued_on, :sent_on) -RETURNING id -` + :visibility, :external_id, :channel_id, :contact_id, :contact_urn_id, :created_on, :modified_on, :next_attempt, :queued_on, :sent_on, :log_uuids) +RETURNING id` func writeMsgToDB(ctx context.Context, b *backend, m *DBMsg, clog *courier.ChannelLog) error { // grab the contact for this msg @@ -162,11 +167,11 @@ func writeMsgToDB(ctx context.Context, b *backend, m *DBMsg, clog *courier.Chann return errors.Wrap(err, "error getting contact for message") } - // set our contact and urn ids from our contact + // set our contact and urn id m.ContactID_ = contact.ID_ m.ContactURNID_ = contact.URNID_ - rows, err := b.db.NamedQueryContext(ctx, insertMsgSQL, m) + rows, err := b.db.NamedQueryContext(ctx, sqlInsertMsg, m) if err != nil { return errors.Wrap(err, "error inserting message") } @@ -192,7 +197,7 @@ func writeMsgToDB(ctx context.Context, b *backend, m *DBMsg, clog *courier.Chann return nil } -const selectMsgSQL = ` +const sqlSelectMsg = ` SELECT org_id, direction, @@ -212,12 +217,12 @@ SELECT modified_on, next_attempt, queued_on, - sent_on + sent_on, + log_uuids FROM msgs_msg WHERE - id = $1 -` + id = $1` const selectChannelSQL = ` SELECT @@ -537,11 +542,12 @@ type DBMsg struct { ChannelUUID_ courier.ChannelUUID `json:"channel_uuid"` ContactName_ string `json:"contact_name"` - NextAttempt_ time.Time `json:"next_attempt" db:"next_attempt"` - CreatedOn_ time.Time `json:"created_on" db:"created_on"` - ModifiedOn_ time.Time `json:"modified_on" db:"modified_on"` - QueuedOn_ time.Time `json:"queued_on" db:"queued_on"` - SentOn_ *time.Time `json:"sent_on" db:"sent_on"` + NextAttempt_ time.Time `json:"next_attempt" db:"next_attempt"` + CreatedOn_ time.Time `json:"created_on" db:"created_on"` + ModifiedOn_ time.Time `json:"modified_on" db:"modified_on"` + QueuedOn_ time.Time `json:"queued_on" db:"queued_on"` + SentOn_ *time.Time `json:"sent_on" db:"sent_on"` + LogUUIDs pq.StringArray `json:"log_uuids" db:"log_uuids"` // fields used to allow courier to update a session's timeout when a message is sent for efficient timeout behavior SessionID_ SessionID `json:"session_id,omitempty"` diff --git a/backends/rapidpro/schema.sql b/backends/rapidpro/schema.sql index 0cf782dd0..bc996125e 100644 --- a/backends/rapidpro/schema.sql +++ b/backends/rapidpro/schema.sql @@ -81,7 +81,8 @@ CREATE TABLE msgs_msg ( org_id integer NOT NULL references orgs_org(id) on delete cascade, metadata text, topup_id integer, - delete_from_counts boolean + delete_from_counts boolean, + log_uuids uuid[] ); DROP TABLE IF EXISTS channels_channellog CASCADE; @@ -108,7 +109,8 @@ CREATE TABLE channels_channelevent ( channel_id integer NOT NULL references channels_channel(id) on delete cascade, contact_id integer NOT NULL references contacts_contact(id) on delete cascade, contact_urn_id integer NOT NULL references contacts_contacturn(id) on delete cascade, - org_id integer NOT NULL references orgs_org(id) on delete cascade + org_id integer NOT NULL references orgs_org(id) on delete cascade, + log_uuids uuid[] ); DROP TABLE IF EXISTS flows_flowsession CASCADE; diff --git a/handler_test.go b/handler_test.go index 11fa876d2..55f31516b 100644 --- a/handler_test.go +++ b/handler_test.go @@ -59,7 +59,7 @@ func (h *dummyHandler) receiveMsg(ctx context.Context, channel courier.Channel, return nil, errors.New("missing from or text") } - msg := h.backend.NewIncomingMsg(channel, urns.URN("tel:"+from), text) + msg := h.backend.NewIncomingMsg(channel, urns.URN("tel:"+from), text, clog) w.WriteHeader(200) w.Write([]byte("ok")) h.backend.WriteMsg(ctx, msg, clog) diff --git a/handlers/africastalking/africastalking.go b/handlers/africastalking/africastalking.go index 1d76d6f76..86320a4df 100644 --- a/handlers/africastalking/africastalking.go +++ b/handlers/africastalking/africastalking.go @@ -73,7 +73,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, form.Text).WithExternalID(form.ID).WithReceivedOn(date) + msg := h.Backend().NewIncomingMsg(channel, urn, form.Text, clog).WithExternalID(form.ID).WithReceivedOn(date) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/blackmyna/blackmyna.go b/handlers/blackmyna/blackmyna.go index e553d737f..d70b2dd99 100644 --- a/handlers/blackmyna/blackmyna.go +++ b/handlers/blackmyna/blackmyna.go @@ -57,7 +57,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, form.Text) + msg := h.Backend().NewIncomingMsg(channel, urn, form.Text, clog) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/bongolive/bongolive.go b/handlers/bongolive/bongolive.go index 527cb4d1b..d1ad22cc1 100644 --- a/handlers/bongolive/bongolive.go +++ b/handlers/bongolive/bongolive.go @@ -96,7 +96,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, form.Message).WithExternalID(form.ID).WithReceivedOn(time.Now().UTC()) + msg := h.Backend().NewIncomingMsg(channel, urn, form.Message, clog).WithExternalID(form.ID).WithReceivedOn(time.Now().UTC()) // and finally queue our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/chikka/chikka.go b/handlers/chikka/chikka.go index 26f240b15..4de7c2f41 100644 --- a/handlers/chikka/chikka.go +++ b/handlers/chikka/chikka.go @@ -94,7 +94,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, form.Message).WithExternalID(form.RequestID).WithReceivedOn(date) + msg := h.Backend().NewIncomingMsg(channel, urn, form.Message, clog).WithExternalID(form.RequestID).WithReceivedOn(date) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/clickatell/clickatell.go b/handlers/clickatell/clickatell.go index 20d969a08..5f6cc6078 100644 --- a/handlers/clickatell/clickatell.go +++ b/handlers/clickatell/clickatell.go @@ -143,7 +143,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, utils.CleanString(text)).WithReceivedOn(date.UTC()).WithExternalID(payload.MessageID) + msg := h.Backend().NewIncomingMsg(channel, urn, utils.CleanString(text), clog).WithReceivedOn(date.UTC()).WithExternalID(payload.MessageID) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/clickmobile/clickmobile.go b/handlers/clickmobile/clickmobile.go index 7267fbacc..8f51b6059 100644 --- a/handlers/clickmobile/clickmobile.go +++ b/handlers/clickmobile/clickmobile.go @@ -77,7 +77,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, payload.Text).WithExternalID(payload.ReferenceID) + msg := h.Backend().NewIncomingMsg(channel, urn, payload.Text, clog).WithExternalID(payload.ReferenceID) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/dart/dart.go b/handlers/dart/dart.go index ff68e5d12..b1a4bd9fc 100644 --- a/handlers/dart/dart.go +++ b/handlers/dart/dart.go @@ -77,7 +77,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, form.Message) + msg := h.Backend().NewIncomingMsg(channel, urn, form.Message, clog) // and finally queue our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/discord/discord.go b/handlers/discord/discord.go index bba5f0805..022fe23f4 100644 --- a/handlers/discord/discord.go +++ b/handlers/discord/discord.go @@ -102,7 +102,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date) + msg := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithReceivedOn(date) for _, attachment := range r.Form["attachments"] { msg.WithAttachment(attachment) diff --git a/handlers/dmark/dmark.go b/handlers/dmark/dmark.go index e7890e1ca..f56ac1c65 100644 --- a/handlers/dmark/dmark.go +++ b/handlers/dmark/dmark.go @@ -68,7 +68,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, form.Text).WithReceivedOn(date) + msg := h.Backend().NewIncomingMsg(channel, urn, form.Text, clog).WithReceivedOn(date) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/external/external.go b/handlers/external/external.go index 959c6c998..92f9f6761 100644 --- a/handlers/external/external.go +++ b/handlers/external/external.go @@ -112,7 +112,7 @@ func (h *handler) receiveStopContact(ctx context.Context, channel courier.Channe urn = urn.Normalize("") // create a stop channel event - channelEvent := h.Backend().NewChannelEvent(channel, courier.StopContact, urn) + channelEvent := h.Backend().NewChannelEvent(channel, courier.StopContact, urn, clog) err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { return nil, err @@ -214,7 +214,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w urn = urn.Normalize(channel.Country()) // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date) + msg := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithReceivedOn(date) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/facebook/facebook.go b/handlers/facebook/facebook.go index 13762c571..17705f379 100644 --- a/handlers/facebook/facebook.go +++ b/handlers/facebook/facebook.go @@ -274,7 +274,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } } - event := h.Backend().NewChannelEvent(channel, courier.Referral, urn).WithOccurredOn(date) + event := h.Backend().NewChannelEvent(channel, courier.Referral, urn, clog).WithOccurredOn(date) // build our extra extra := map[string]interface{}{ @@ -296,7 +296,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h if msg.Postback.Referral.Ref != "" { eventType = courier.Referral } - event := h.Backend().NewChannelEvent(channel, eventType, urn).WithOccurredOn(date) + event := h.Backend().NewChannelEvent(channel, eventType, urn, clog).WithOccurredOn(date) // build our extra extra := map[string]interface{}{ @@ -327,7 +327,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } else if msg.Referral != nil { // this is an incoming referral - event := h.Backend().NewChannelEvent(channel, courier.Referral, urn).WithOccurredOn(date) + event := h.Backend().NewChannelEvent(channel, courier.Referral, urn, clog).WithOccurredOn(date) // build our extra extra := map[string]interface{}{ @@ -391,7 +391,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } // create our message - ev := h.Backend().NewIncomingMsg(channel, urn, text).WithExternalID(msg.Message.MID).WithReceivedOn(date) + ev := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithExternalID(msg.Message.MID).WithReceivedOn(date) event := h.Backend().CheckExternalIDSeen(ev) // add any attachment URL found diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 1d28e558a..9eb53e9f9 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -463,7 +463,7 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri } // create our message - ev := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date).WithExternalID(msg.ID).WithContactName(contactNames[msg.From]) + ev := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithReceivedOn(date).WithExternalID(msg.ID).WithContactName(contactNames[msg.From]) event := h.Backend().CheckExternalIDSeen(ev) // we had an error downloading media @@ -584,7 +584,7 @@ func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel c } } - event := h.Backend().NewChannelEvent(channel, courier.Referral, urn).WithOccurredOn(date) + event := h.Backend().NewChannelEvent(channel, courier.Referral, urn, clog).WithOccurredOn(date) // build our extra extra := map[string]interface{}{ @@ -606,7 +606,7 @@ func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel c if msg.Postback.Referral.Ref != "" { eventType = courier.Referral } - event := h.Backend().NewChannelEvent(channel, eventType, urn).WithOccurredOn(date) + event := h.Backend().NewChannelEvent(channel, eventType, urn, clog).WithOccurredOn(date) // build our extra extra := map[string]interface{}{ @@ -637,7 +637,7 @@ func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel c } else if msg.Referral != nil { // this is an incoming referral - event := h.Backend().NewChannelEvent(channel, courier.Referral, urn).WithOccurredOn(date) + event := h.Backend().NewChannelEvent(channel, courier.Referral, urn, clog).WithOccurredOn(date) // build our extra extra := map[string]interface{}{ @@ -713,7 +713,7 @@ func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel c } // create our message - ev := h.Backend().NewIncomingMsg(channel, urn, text).WithExternalID(msg.Message.MID).WithReceivedOn(date) + ev := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithExternalID(msg.Message.MID).WithReceivedOn(date) event := h.Backend().CheckExternalIDSeen(ev) // add any attachment URL found diff --git a/handlers/firebase/firebase.go b/handlers/firebase/firebase.go index fc7e1e7f7..a11fc21e0 100644 --- a/handlers/firebase/firebase.go +++ b/handlers/firebase/firebase.go @@ -76,7 +76,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - dbMsg := h.Backend().NewIncomingMsg(channel, urn, form.Msg).WithReceivedOn(date).WithContactName(form.Name).WithURNAuth(form.FCMToken) + dbMsg := h.Backend().NewIncomingMsg(channel, urn, form.Msg, clog).WithReceivedOn(date).WithContactName(form.Name).WithURNAuth(form.FCMToken) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{dbMsg}, w, r, clog) diff --git a/handlers/freshchat/freshchat.go b/handlers/freshchat/freshchat.go index d474a42f1..841ecefea 100644 --- a/handlers/freshchat/freshchat.go +++ b/handlers/freshchat/freshchat.go @@ -91,7 +91,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date) + msg := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithReceivedOn(date) //add image if mediaURL != "" { diff --git a/handlers/generic.go b/handlers/generic.go index 2ee529147..6e8b648ec 100644 --- a/handlers/generic.go +++ b/handlers/generic.go @@ -28,7 +28,7 @@ func NewTelReceiveHandler(h *BaseHandler, fromField string, bodyField string) co return nil, WriteAndLogRequestError(ctx, h, c, w, r, err) } // build our msg - msg := h.Backend().NewIncomingMsg(c, urn, body).WithReceivedOn(time.Now().UTC()) + msg := h.Backend().NewIncomingMsg(c, urn, body, clog).WithReceivedOn(time.Now().UTC()) return WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } } diff --git a/handlers/globe/globe.go b/handlers/globe/globe.go index 29e4e998a..71c23592c 100644 --- a/handlers/globe/globe.go +++ b/handlers/globe/globe.go @@ -103,7 +103,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, err) } - msg := h.Backend().NewIncomingMsg(c, urn, glMsg.Message).WithExternalID(glMsg.MessageID).WithReceivedOn(date) + msg := h.Backend().NewIncomingMsg(c, urn, glMsg.Message, clog).WithExternalID(glMsg.MessageID).WithReceivedOn(date) msgs = append(msgs, msg) } diff --git a/handlers/highconnection/highconnection.go b/handlers/highconnection/highconnection.go index 278faeec0..2f994c17c 100644 --- a/handlers/highconnection/highconnection.go +++ b/handlers/highconnection/highconnection.go @@ -74,7 +74,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w text, _ = new(mime.WordDecoder).DecodeHeader(text) // build our Message - msg := h.Backend().NewIncomingMsg(channel, urn, utils.CleanString(text)).WithReceivedOn(date.UTC()) + msg := h.Backend().NewIncomingMsg(channel, urn, utils.CleanString(text), clog).WithReceivedOn(date.UTC()) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/hormuud/hormuud.go b/handlers/hormuud/hormuud.go index c41a5b494..476670637 100644 --- a/handlers/hormuud/hormuud.go +++ b/handlers/hormuud/hormuud.go @@ -66,7 +66,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, err) } - msg := h.Backend().NewIncomingMsg(c, urn, payload.MessageText).WithReceivedOn(date) + msg := h.Backend().NewIncomingMsg(c, urn, payload.MessageText, clog).WithReceivedOn(date) return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } diff --git a/handlers/i2sms/i2sms.go b/handlers/i2sms/i2sms.go index 458f4b0d1..4d8843d3c 100644 --- a/handlers/i2sms/i2sms.go +++ b/handlers/i2sms/i2sms.go @@ -61,7 +61,7 @@ func (h *handler) receive(ctx context.Context, c courier.Channel, w http.Respons } // build our msg - msg := h.Backend().NewIncomingMsg(c, urn, body).WithReceivedOn(time.Now().UTC()) + msg := h.Backend().NewIncomingMsg(c, urn, body, clog).WithReceivedOn(time.Now().UTC()) return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } diff --git a/handlers/infobip/infobip.go b/handlers/infobip/infobip.go index c137f7e69..4f1a68360 100644 --- a/handlers/infobip/infobip.go +++ b/handlers/infobip/infobip.go @@ -162,7 +162,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our infobipMessage - msg := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date).WithExternalID(messageID) + msg := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithReceivedOn(date).WithExternalID(messageID) msgs = append(msgs, msg) } diff --git a/handlers/jasmin/jasmin.go b/handlers/jasmin/jasmin.go index 825d951e5..851e828cb 100644 --- a/handlers/jasmin/jasmin.go +++ b/handlers/jasmin/jasmin.go @@ -94,7 +94,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. } // build our msg - msg := h.Backend().NewIncomingMsg(c, urn, text).WithExternalID(form.ID).WithReceivedOn(time.Now().UTC()) + msg := h.Backend().NewIncomingMsg(c, urn, text, clog).WithExternalID(form.ID).WithReceivedOn(time.Now().UTC()) // and finally queue our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 82635c519..ea8b7422f 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -128,7 +128,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w // subscribe event, trigger a new conversation if payload.MsgType == "event" && payload.Event == "subscribe" { - channelEvent := h.Backend().NewChannelEvent(channel, courier.NewConversation, urn) + channelEvent := h.Backend().NewChannelEvent(channel, courier.NewConversation, urn, clog) err := h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { @@ -144,7 +144,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // create our message - msg := h.Backend().NewIncomingMsg(channel, urn, payload.Content).WithExternalID(payload.MsgID).WithReceivedOn(date) + msg := h.Backend().NewIncomingMsg(channel, urn, payload.Content, clog).WithExternalID(payload.MsgID).WithReceivedOn(date) if payload.MsgType == "image" || payload.MsgType == "video" || payload.MsgType == "voice" { mediaURL := buildMediaURL(payload.MediaID) msg.WithAttachment(mediaURL) diff --git a/handlers/junebug/junebug.go b/handlers/junebug/junebug.go index b5873ceb2..545868ba9 100644 --- a/handlers/junebug/junebug.go +++ b/handlers/junebug/junebug.go @@ -83,7 +83,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, err) } - msg := h.Backend().NewIncomingMsg(c, urn, payload.Content).WithExternalID(payload.MessageID).WithReceivedOn(date.UTC()) + msg := h.Backend().NewIncomingMsg(c, urn, payload.Content, clog).WithExternalID(payload.MessageID).WithReceivedOn(date.UTC()) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/kaleyra/kaleyra.go b/handlers/kaleyra/kaleyra.go index ed1f5de91..7a1f56c11 100644 --- a/handlers/kaleyra/kaleyra.go +++ b/handlers/kaleyra/kaleyra.go @@ -95,7 +95,7 @@ func (h *handler) receiveMsg(ctx context.Context, channel courier.Channel, w htt // build msg date := time.Unix(ts, 0).UTC() - msg := h.Backend().NewIncomingMsg(channel, urn, form.Body).WithReceivedOn(date).WithContactName(form.Name) + msg := h.Backend().NewIncomingMsg(channel, urn, form.Body, clog).WithReceivedOn(date).WithContactName(form.Name) if form.MediaURL != "" { msg.WithAttachment(form.MediaURL) diff --git a/handlers/kannel/kannel.go b/handlers/kannel/kannel.go index e5b7d7d49..861cb04f1 100644 --- a/handlers/kannel/kannel.go +++ b/handlers/kannel/kannel.go @@ -74,7 +74,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, form.Message).WithExternalID(form.ID).WithReceivedOn(date) + msg := h.Backend().NewIncomingMsg(channel, urn, form.Message, clog).WithExternalID(form.ID).WithReceivedOn(date) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/line/line.go b/handlers/line/line.go index 784328f4c..909ac6a7b 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -159,7 +159,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } - msg := h.Backend().NewIncomingMsg(channel, urn, text).WithExternalID(lineEvent.ReplyToken).WithReceivedOn(date) + msg := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithExternalID(lineEvent.ReplyToken).WithReceivedOn(date) if mediaURL != "" { msg.WithAttachment(mediaURL) diff --git a/handlers/m3tech/m3tech.go b/handlers/m3tech/m3tech.go index d7499fb54..ce178ccd3 100644 --- a/handlers/m3tech/m3tech.go +++ b/handlers/m3tech/m3tech.go @@ -57,7 +57,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. } // build our msg - msg := h.Backend().NewIncomingMsg(c, urn, body).WithReceivedOn(time.Now().UTC()) + msg := h.Backend().NewIncomingMsg(c, urn, body, clog).WithReceivedOn(time.Now().UTC()) return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } diff --git a/handlers/macrokiosk/macrokiosk.go b/handlers/macrokiosk/macrokiosk.go index 2e4eb892f..74c9244cf 100644 --- a/handlers/macrokiosk/macrokiosk.go +++ b/handlers/macrokiosk/macrokiosk.go @@ -128,7 +128,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, form.Text).WithExternalID(form.MsgID).WithReceivedOn(date.UTC()) + msg := h.Backend().NewIncomingMsg(channel, urn, form.Text, clog).WithExternalID(form.MsgID).WithReceivedOn(date.UTC()) // and write it return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/mblox/mblox.go b/handlers/mblox/mblox.go index ecf2332f3..220e50e9a 100644 --- a/handlers/mblox/mblox.go +++ b/handlers/mblox/mblox.go @@ -98,7 +98,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } // build our Message - msg := h.Backend().NewIncomingMsg(channel, urn, payload.Body).WithReceivedOn(date.UTC()).WithExternalID(payload.ID) + msg := h.Backend().NewIncomingMsg(channel, urn, payload.Body, clog).WithReceivedOn(date.UTC()).WithExternalID(payload.ID) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/mtarget/mtarget.go b/handlers/mtarget/mtarget.go index bf8f62482..3b87e060f 100644 --- a/handlers/mtarget/mtarget.go +++ b/handlers/mtarget/mtarget.go @@ -133,7 +133,7 @@ func (h *handler) receiveMsg(ctx context.Context, c courier.Channel, w http.Resp // if this a stop command, shortcut stopping that contact if keyword == "Stop" { - stop := h.Backend().NewChannelEvent(c, courier.StopContact, urn) + stop := h.Backend().NewChannelEvent(c, courier.StopContact, urn, clog) err := h.Backend().WriteChannelEvent(ctx, stop, clog) if err != nil { return nil, err @@ -142,7 +142,7 @@ func (h *handler) receiveMsg(ctx context.Context, c courier.Channel, w http.Resp } // otherwise, create our incoming message and write that - msg := h.Backend().NewIncomingMsg(c, urn, text).WithReceivedOn(time.Now().UTC()) + msg := h.Backend().NewIncomingMsg(c, urn, text, clog).WithReceivedOn(time.Now().UTC()) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } diff --git a/handlers/nexmo/nexmo.go b/handlers/nexmo/nexmo.go index 28b89f7fe..716fc6454 100644 --- a/handlers/nexmo/nexmo.go +++ b/handlers/nexmo/nexmo.go @@ -111,7 +111,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, form.Text) + msg := h.Backend().NewIncomingMsg(channel, urn, form.Text, clog) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } diff --git a/handlers/novo/novo.go b/handlers/novo/novo.go index 7c8848f5d..afe61a9a2 100644 --- a/handlers/novo/novo.go +++ b/handlers/novo/novo.go @@ -73,7 +73,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. } // build our msg - msg := h.Backend().NewIncomingMsg(c, urn, body).WithReceivedOn(time.Now().UTC()) + msg := h.Backend().NewIncomingMsg(c, urn, body, clog).WithReceivedOn(time.Now().UTC()) return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } diff --git a/handlers/playmobile/playmobile.go b/handlers/playmobile/playmobile.go index e3d8256eb..b32bb0ac3 100644 --- a/handlers/playmobile/playmobile.go +++ b/handlers/playmobile/playmobile.go @@ -136,7 +136,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. if pmMsg.Content.Text == "" { return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, errors.New("no text")) } - msg := h.Backend().NewIncomingMsg(c, urn, pmMsg.Content.Text).WithExternalID(pmMsg.ID) + msg := h.Backend().NewIncomingMsg(c, urn, pmMsg.Content.Text, clog).WithExternalID(pmMsg.ID) msgs = append(msgs, msg) } diff --git a/handlers/plivo/plivo.go b/handlers/plivo/plivo.go index 1d9f7ce44..bb1ec18e9 100644 --- a/handlers/plivo/plivo.go +++ b/handlers/plivo/plivo.go @@ -122,7 +122,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, form.Text).WithExternalID(form.MessageUUID) + msg := h.Backend().NewIncomingMsg(channel, urn, form.Text, clog).WithExternalID(form.MessageUUID) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } diff --git a/handlers/rocketchat/rocketchat.go b/handlers/rocketchat/rocketchat.go index 11ae3ca2a..ab6352e0e 100644 --- a/handlers/rocketchat/rocketchat.go +++ b/handlers/rocketchat/rocketchat.go @@ -80,7 +80,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } - msg := h.Backend().NewIncomingMsg(channel, urn, payload.Text).WithContactName(payload.User.FullName) + msg := h.Backend().NewIncomingMsg(channel, urn, payload.Text, clog).WithContactName(payload.User.FullName) for _, attachment := range payload.Attachments { msg.WithAttachment(attachment.URL) } diff --git a/handlers/shaqodoon/shaqodoon.go b/handlers/shaqodoon/shaqodoon.go index 20edb24fc..eb0b62bce 100644 --- a/handlers/shaqodoon/shaqodoon.go +++ b/handlers/shaqodoon/shaqodoon.go @@ -78,7 +78,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, form.Text).WithReceivedOn(date) + msg := h.Backend().NewIncomingMsg(channel, urn, form.Text, clog).WithReceivedOn(date) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index 778e2680e..ce0adfcdc 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -94,7 +94,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } text := payload.Event.Text - msg := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date).WithExternalID(payload.EventID) + msg := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithReceivedOn(date).WithExternalID(payload.EventID) for _, attURL := range attachmentURLs { msg.WithAttachment(attURL) diff --git a/handlers/smscentral/smscentral.go b/handlers/smscentral/smscentral.go index 87d7ffbec..a90e22f81 100644 --- a/handlers/smscentral/smscentral.go +++ b/handlers/smscentral/smscentral.go @@ -57,7 +57,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, form.Message) + msg := h.Backend().NewIncomingMsg(channel, urn, form.Message, clog) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } diff --git a/handlers/start/start.go b/handlers/start/start.go index 738ef1d94..46f81369d 100644 --- a/handlers/start/start.go +++ b/handlers/start/start.go @@ -81,7 +81,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w date := time.Unix(ts, 0).UTC() // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, payload.Body.Text).WithReceivedOn(date) + msg := h.Backend().NewIncomingMsg(channel, urn, payload.Body.Text, clog).WithReceivedOn(date) // and write it return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index 4f6127bf7..e8f2240ea 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -78,7 +78,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w // this is a start command, trigger a new conversation if text == "/start" { - event := h.Backend().NewChannelEvent(channel, courier.NewConversation, urn).WithContactName(name).WithOccurredOn(date) + event := h.Backend().NewChannelEvent(channel, courier.NewConversation, urn, clog).WithContactName(name).WithOccurredOn(date) err = h.Backend().WriteChannelEvent(ctx, event, clog) if err != nil { return nil, err @@ -131,7 +131,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date).WithExternalID(fmt.Sprintf("%d", payload.Message.MessageID)).WithContactName(name) + msg := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithReceivedOn(date).WithExternalID(fmt.Sprintf("%d", payload.Message.MessageID)).WithContactName(name) if mediaURL != "" { msg.WithAttachment(mediaURL) @@ -230,7 +230,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendMessage", form, msgKeyBoard, clog) if botBlocked { status.SetStatus(courier.MsgFailed) - channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) + channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN(), clog) err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) return status, err } @@ -256,7 +256,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendPhoto", form, attachmentKeyBoard, clog) if botBlocked { status.SetStatus(courier.MsgFailed) - channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) + channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN(), clog) err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) return status, err } @@ -272,7 +272,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendVideo", form, attachmentKeyBoard, clog) if botBlocked { status.SetStatus(courier.MsgFailed) - channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) + channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN(), clog) err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) return status, err } @@ -288,7 +288,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendAudio", form, attachmentKeyBoard, clog) if botBlocked { status.SetStatus(courier.MsgFailed) - channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) + channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN(), clog) err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) return status, err } @@ -304,7 +304,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann externalID, botBlocked, err := h.sendMsgPart(msg, authToken, "sendDocument", form, attachmentKeyBoard, clog) if botBlocked { status.SetStatus(courier.MsgFailed) - channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) + channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN(), clog) err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) return status, err } diff --git a/handlers/telesom/telesom.go b/handlers/telesom/telesom.go index c614704a1..58b6b50e8 100644 --- a/handlers/telesom/telesom.go +++ b/handlers/telesom/telesom.go @@ -57,7 +57,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - dbMsg := h.Backend().NewIncomingMsg(channel, urn, form.Message) + dbMsg := h.Backend().NewIncomingMsg(channel, urn, form.Message, clog) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{dbMsg}, w, r, clog) diff --git a/handlers/thinq/thinq.go b/handlers/thinq/thinq.go index e62dcc9e0..6d2940ebf 100644 --- a/handlers/thinq/thinq.go +++ b/handlers/thinq/thinq.go @@ -73,12 +73,12 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w var msg courier.Msg if form.Type == "sms" { - msg = h.Backend().NewIncomingMsg(channel, urn, form.Message) + msg = h.Backend().NewIncomingMsg(channel, urn, form.Message, clog) } else if form.Type == "mms" { if strings.HasPrefix(form.Message, "http://") || strings.HasPrefix(form.Message, "https://") { - msg = h.Backend().NewIncomingMsg(channel, urn, "").WithAttachment(form.Message) + msg = h.Backend().NewIncomingMsg(channel, urn, "", clog).WithAttachment(form.Message) } else { - msg = h.Backend().NewIncomingMsg(channel, urn, "").WithAttachment("data:" + form.Message) + msg = h.Backend().NewIncomingMsg(channel, urn, "", clog).WithAttachment("data:" + form.Message) } } else { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, fmt.Errorf("unknown message type: %s", form.Type)) diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index 5cf859c92..800eb0c99 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -129,7 +129,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, text).WithExternalID(form.MessageSID) + msg := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithExternalID(form.MessageSID) // process any attached media for i := 0; i < form.NumMedia; i++ { @@ -188,7 +188,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // create a stop channel event - channelEvent := h.Backend().NewChannelEvent(channel, courier.StopContact, urn) + channelEvent := h.Backend().NewChannelEvent(channel, courier.StopContact, urn, clog) err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { return nil, err @@ -279,7 +279,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann status.SetStatus(courier.MsgFailed) // create a stop channel event - channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) + channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN(), clog) err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { return nil, err diff --git a/handlers/twitter/twitter.go b/handlers/twitter/twitter.go index 4deec7983..2875a98ea 100644 --- a/handlers/twitter/twitter.go +++ b/handlers/twitter/twitter.go @@ -191,7 +191,7 @@ func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.Re text := strings.Replace(entry.MessageCreate.MessageData.Text, "&", "&", -1) // create our message - msg := h.Backend().NewIncomingMsg(c, urn, text).WithExternalID(entry.ID).WithReceivedOn(date).WithContactName(user.Name) + msg := h.Backend().NewIncomingMsg(c, urn, text, clog).WithExternalID(entry.ID).WithReceivedOn(date).WithContactName(user.Name) // if we have an attachment, add that as well if entry.MessageCreate.MessageData.Attachment != nil { diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index b63a339f2..b1c44abf6 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -121,7 +121,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } // build the channel event - channelEvent := h.Backend().NewChannelEvent(channel, courier.WelcomeMessage, urn).WithContactName(ContactName) + channelEvent := h.Backend().NewChannelEvent(channel, courier.WelcomeMessage, urn, clog).WithContactName(ContactName) err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { @@ -141,7 +141,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } // build the channel event - channelEvent := h.Backend().NewChannelEvent(channel, courier.NewConversation, urn).WithContactName(ContactName) + channelEvent := h.Backend().NewChannelEvent(channel, courier.NewConversation, urn, clog).WithContactName(ContactName) err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { @@ -159,7 +159,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } // build the channel event - channelEvent := h.Backend().NewChannelEvent(channel, courier.StopContact, urn) + channelEvent := h.Backend().NewChannelEvent(channel, courier.StopContact, urn, clog) err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { @@ -227,7 +227,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, text).WithExternalID(fmt.Sprintf("%d", payload.MessageToken)).WithContactName(contactName) + msg := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithExternalID(fmt.Sprintf("%d", payload.MessageToken)).WithContactName(contactName) if mediaURL != "" { msg.WithAttachment(mediaURL) } diff --git a/handlers/vk/vk.go b/handlers/vk/vk.go index 72aec72d9..43c90b3cf 100644 --- a/handlers/vk/vk.go +++ b/handlers/vk/vk.go @@ -250,7 +250,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w date := time.Unix(payload.Object.Message.Date, 0).UTC() text := payload.Object.Message.Text externalId := strconv.FormatInt(payload.Object.Message.Id, 10) - msg := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date).WithExternalID(externalId) + msg := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithReceivedOn(date).WithExternalID(externalId) event := h.Backend().CheckExternalIDSeen(msg) if attachment := takeFirstAttachmentUrl(*payload); attachment != "" { diff --git a/handlers/wavy/wavy.go b/handlers/wavy/wavy.go index 2a7e83ef6..474887502 100644 --- a/handlers/wavy/wavy.go +++ b/handlers/wavy/wavy.go @@ -126,7 +126,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, payload.Message).WithExternalID(payload.ID).WithReceivedOn(date.UTC()) + msg := h.Backend().NewIncomingMsg(channel, urn, payload.Message, clog).WithExternalID(payload.ID).WithReceivedOn(date.UTC()) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index 2e094f2e3..c2b37a5a2 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -187,7 +187,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w // subscribe event, trigger a new conversation if payload.MsgType == "event" && payload.Event == "subscribe" { - channelEvent := h.Backend().NewChannelEvent(channel, courier.NewConversation, urn) + channelEvent := h.Backend().NewChannelEvent(channel, courier.NewConversation, urn, clog) err := h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { @@ -203,7 +203,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // create our message - msg := h.Backend().NewIncomingMsg(channel, urn, payload.Content).WithExternalID(payload.MsgID).WithReceivedOn(date) + msg := h.Backend().NewIncomingMsg(channel, urn, payload.Content, clog).WithExternalID(payload.MsgID).WithReceivedOn(date) if payload.MsgType == "image" || payload.MsgType == "video" || payload.MsgType == "voice" { mediaURL := buildMediaURL(payload.MediaID) msg.WithAttachment(mediaURL) diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index 1ebb70195..7de47a483 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -238,7 +238,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } // create our message - ev := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date).WithExternalID(msg.ID).WithContactName(contactNames[msg.From]) + ev := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithReceivedOn(date).WithExternalID(msg.ID).WithContactName(contactNames[msg.From]) event := h.Backend().CheckExternalIDSeen(ev) // we had an error downloading media diff --git a/handlers/yo/yo.go b/handlers/yo/yo.go index f1ab64cbb..d6b88ee57 100644 --- a/handlers/yo/yo.go +++ b/handlers/yo/yo.go @@ -90,7 +90,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - dbMsg := h.Backend().NewIncomingMsg(channel, urn, form.Message).WithReceivedOn(date) + dbMsg := h.Backend().NewIncomingMsg(channel, urn, form.Message, clog).WithReceivedOn(date) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{dbMsg}, w, r, clog) @@ -143,7 +143,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann status.SetStatus(courier.MsgFailed) // create a stop channel event - channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN()) + channelEvent := h.Backend().NewChannelEvent(msg.Channel(), courier.StopContact, msg.URN(), clog) err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) if err != nil { return nil, err diff --git a/handlers/zenvia/zenvia.go b/handlers/zenvia/zenvia.go index da6dd822e..2514cb9c3 100644 --- a/handlers/zenvia/zenvia.go +++ b/handlers/zenvia/zenvia.go @@ -126,7 +126,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, text).WithExternalID(payload.Message.ID).WithReceivedOn(date.UTC()).WithContactName(contactName) + msg := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithExternalID(payload.Message.ID).WithReceivedOn(date.UTC()).WithContactName(contactName) if mediaURL != "" { msg.WithAttachment(mediaURL) } diff --git a/handlers/zenviaold/zenviaold.go b/handlers/zenviaold/zenviaold.go index fa2e90847..602029544 100644 --- a/handlers/zenviaold/zenviaold.go +++ b/handlers/zenviaold/zenviaold.go @@ -137,7 +137,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, payload.CallbackMORequest.Text).WithExternalID(payload.CallbackMORequest.ID).WithReceivedOn(date.UTC()) + msg := h.Backend().NewIncomingMsg(channel, urn, payload.CallbackMORequest.Text, clog).WithExternalID(payload.CallbackMORequest.ID).WithReceivedOn(date.UTC()) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } diff --git a/test/backend.go b/test/backend.go index c3a1d3e6f..d2772c470 100644 --- a/test/backend.go +++ b/test/backend.go @@ -120,7 +120,7 @@ func (mb *MockBackend) DeleteMsgWithExternalID(ctx context.Context, channel cour } // NewIncomingMsg creates a new message from the given params -func (mb *MockBackend) NewIncomingMsg(channel courier.Channel, urn urns.URN, text string) courier.Msg { +func (mb *MockBackend) NewIncomingMsg(channel courier.Channel, urn urns.URN, text string, clog *courier.ChannelLog) courier.Msg { return &mockMsg{channel: channel, urn: urn, text: text} } @@ -240,7 +240,7 @@ func (mb *MockBackend) WriteMsgStatus(ctx context.Context, status courier.MsgSta } // NewChannelEvent creates a new channel event with the passed in parameters -func (mb *MockBackend) NewChannelEvent(channel courier.Channel, eventType courier.ChannelEventType, urn urns.URN) courier.ChannelEvent { +func (mb *MockBackend) NewChannelEvent(channel courier.Channel, eventType courier.ChannelEventType, urn urns.URN, clog *courier.ChannelLog) courier.ChannelEvent { return &mockChannelEvent{ channel: channel, eventType: eventType, From edfe69774289c0f2f68a36449273b0213c48cdc1 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 7 Sep 2022 14:17:02 -0500 Subject: [PATCH 140/294] Append channel log UUIDs on status writes --- backend.go | 4 +- backends/rapidpro/backend.go | 10 ++-- backends/rapidpro/backend_test.go | 69 ++++++++++++++--------- backends/rapidpro/status.go | 28 +++++---- handler_test.go | 2 +- handlers/africastalking/africastalking.go | 4 +- handlers/arabiacell/arabiacell.go | 2 +- handlers/blackmyna/blackmyna.go | 4 +- handlers/bongolive/bongolive.go | 4 +- handlers/burstsms/burstsms.go | 2 +- handlers/chikka/chikka.go | 4 +- handlers/clickatell/clickatell.go | 4 +- handlers/clickmobile/clickmobile.go | 2 +- handlers/clicksend/clicksend.go | 2 +- handlers/dart/dart.go | 4 +- handlers/discord/discord.go | 4 +- handlers/dmark/dmark.go | 4 +- handlers/external/external.go | 4 +- handlers/facebook/facebook.go | 4 +- handlers/facebookapp/facebookapp.go | 8 +-- handlers/firebase/firebase.go | 2 +- handlers/freshchat/freshchat.go | 2 +- handlers/generic.go | 2 +- handlers/globe/globe.go | 2 +- handlers/highconnection/highconnection.go | 4 +- handlers/hormuud/hormuud.go | 2 +- handlers/i2sms/i2sms.go | 2 +- handlers/infobip/infobip.go | 4 +- handlers/jasmin/jasmin.go | 4 +- handlers/jiochat/jiochat.go | 2 +- handlers/junebug/junebug.go | 4 +- handlers/kaleyra/kaleyra.go | 4 +- handlers/kannel/kannel.go | 4 +- handlers/line/line.go | 2 +- handlers/m3tech/m3tech.go | 2 +- handlers/macrokiosk/macrokiosk.go | 4 +- handlers/mblox/mblox.go | 4 +- handlers/messangi/messangi.go | 2 +- handlers/mtarget/mtarget.go | 2 +- handlers/nexmo/nexmo.go | 4 +- handlers/novo/novo.go | 2 +- handlers/playmobile/playmobile.go | 2 +- handlers/plivo/plivo.go | 4 +- handlers/redrabbit/redrabbit.go | 2 +- handlers/rocketchat/rocketchat.go | 2 +- handlers/shaqodoon/shaqodoon.go | 2 +- handlers/slack/slack.go | 2 +- handlers/smscentral/smscentral.go | 2 +- handlers/start/start.go | 2 +- handlers/telegram/telegram.go | 2 +- handlers/telesom/telesom.go | 2 +- handlers/thinq/thinq.go | 4 +- handlers/twiml/twiml.go | 6 +- handlers/twitter/twitter.go | 2 +- handlers/viber/viber.go | 4 +- handlers/vk/vk.go | 2 +- handlers/wavy/wavy.go | 6 +- handlers/wechat/wechat.go | 2 +- handlers/whatsapp/whatsapp.go | 4 +- handlers/yo/yo.go | 2 +- handlers/zenvia/zenvia.go | 4 +- handlers/zenviaold/zenviaold.go | 4 +- sender.go | 4 +- test/backend.go | 4 +- 64 files changed, 158 insertions(+), 141 deletions(-) diff --git a/backend.go b/backend.go index f35b98ed2..9ba79e93b 100644 --- a/backend.go +++ b/backend.go @@ -48,10 +48,10 @@ type Backend interface { WriteMsg(context.Context, Msg, *ChannelLog) error // NewMsgStatusForID creates a new Status object for the given message id - NewMsgStatusForID(Channel, MsgID, MsgStatusValue) MsgStatus + NewMsgStatusForID(Channel, MsgID, MsgStatusValue, *ChannelLog) MsgStatus // NewMsgStatusForExternalID creates a new Status object for the given external id - NewMsgStatusForExternalID(Channel, string, MsgStatusValue) MsgStatus + NewMsgStatusForExternalID(Channel, string, MsgStatusValue, *ChannelLog) MsgStatus // WriteMsgStatus writes the passed in status update to our backend WriteMsgStatus(context.Context, MsgStatus) error diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index d61cf3b3d..fed8f9c2f 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -38,7 +38,7 @@ const msgQueueName = "msgs" const sentSetName = "msgs_sent_%s" // our timeout for backend operations -const backendTimeout = time.Second * 20 +const backendTimeout = time.Second * 2000 var uuidRegex = regexp.MustCompile(`[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`) @@ -266,13 +266,13 @@ func (b *backend) WriteMsg(ctx context.Context, m courier.Msg, clog *courier.Cha } // NewStatusUpdateForID creates a new Status object for the given message id -func (b *backend) NewMsgStatusForID(channel courier.Channel, id courier.MsgID, status courier.MsgStatusValue) courier.MsgStatus { - return newMsgStatus(channel, id, "", status) +func (b *backend) NewMsgStatusForID(channel courier.Channel, id courier.MsgID, status courier.MsgStatusValue, clog *courier.ChannelLog) courier.MsgStatus { + return newMsgStatus(channel, id, "", status, clog) } // NewStatusUpdateForID creates a new Status object for the given message id -func (b *backend) NewMsgStatusForExternalID(channel courier.Channel, externalID string, status courier.MsgStatusValue) courier.MsgStatus { - return newMsgStatus(channel, courier.NilMsgID, externalID, status) +func (b *backend) NewMsgStatusForExternalID(channel courier.Channel, externalID string, status courier.MsgStatusValue, clog *courier.ChannelLog) courier.MsgStatus { + return newMsgStatus(channel, courier.NilMsgID, externalID, status, clog) } // WriteMsgStatus writes the passed in MsgStatus to our store diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 1061ad724..98a34bd08 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -18,6 +18,7 @@ import ( "time" "github.com/gomodule/redigo/redis" + "github.com/lib/pq" "github.com/nyaruka/courier" "github.com/nyaruka/courier/queue" "github.com/nyaruka/courier/test" @@ -190,29 +191,30 @@ func (ts *BackendTestSuite) TestMsgUnmarshal() { func (ts *BackendTestSuite) TestCheckMsgExists() { knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) // check with invalid message id - err := checkMsgExists(ts.b, ts.b.NewMsgStatusForID(knChannel, courier.NewMsgID(-1), courier.MsgStatusValue("S"))) + err := checkMsgExists(ts.b, ts.b.NewMsgStatusForID(knChannel, courier.NewMsgID(-1), courier.MsgStatusValue("S"), clog)) ts.Equal(err, courier.ErrMsgNotFound) // check with valid message id - err = checkMsgExists(ts.b, ts.b.NewMsgStatusForID(knChannel, courier.NewMsgID(10000), courier.MsgStatusValue("S"))) + err = checkMsgExists(ts.b, ts.b.NewMsgStatusForID(knChannel, courier.NewMsgID(10000), courier.MsgStatusValue("S"), clog)) ts.Nil(err) // only outgoing messages are matched - err = checkMsgExists(ts.b, ts.b.NewMsgStatusForID(knChannel, courier.NewMsgID(10002), courier.MsgStatusValue("S"))) + err = checkMsgExists(ts.b, ts.b.NewMsgStatusForID(knChannel, courier.NewMsgID(10002), courier.MsgStatusValue("S"), clog)) ts.Equal(err, courier.ErrMsgNotFound) // check with invalid external id - err = checkMsgExists(ts.b, ts.b.NewMsgStatusForExternalID(knChannel, "ext-invalid", courier.MsgStatusValue("S"))) + err = checkMsgExists(ts.b, ts.b.NewMsgStatusForExternalID(knChannel, "ext-invalid", courier.MsgStatusValue("S"), clog)) ts.Equal(err, courier.ErrMsgNotFound) // only outgoing messages are matched - err = checkMsgExists(ts.b, ts.b.NewMsgStatusForExternalID(knChannel, "ext2", courier.MsgStatusValue("S"))) + err = checkMsgExists(ts.b, ts.b.NewMsgStatusForExternalID(knChannel, "ext2", courier.MsgStatusValue("S"), clog)) ts.Equal(err, courier.ErrMsgNotFound) // check with valid external id - status := ts.b.NewMsgStatusForExternalID(knChannel, "ext1", courier.MsgStatusValue("S")) + status := ts.b.NewMsgStatusForExternalID(knChannel, "ext1", courier.MsgStatusValue("S"), clog) err = checkMsgExists(ts.b, status) ts.Nil(err) } @@ -511,7 +513,6 @@ func (ts *BackendTestSuite) TestContactURNPriority() { func (ts *BackendTestSuite) TestMsgStatus() { ctx := context.Background() channel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel) now := time.Now().In(time.UTC) time.Sleep(2 * time.Millisecond) @@ -519,7 +520,8 @@ func (ts *BackendTestSuite) TestMsgStatus() { ts.b.db.MustExec(`UPDATE msgs_msg SET status = 'Q', sent_on = NULL WHERE id = $1`, 10001) // update to WIRED using id and provide new external ID - status := ts.b.NewMsgStatusForID(channel, courier.NewMsgID(10001), courier.MsgWired) + clog1 := courier.NewChannelLog(courier.ChannelLogTypeMsgStatus, channel) + status := ts.b.NewMsgStatusForID(channel, courier.NewMsgID(10001), courier.MsgWired, clog1) status.SetExternalID("ext0") err := ts.b.WriteMsgStatus(ctx, status) ts.NoError(err) @@ -532,11 +534,13 @@ func (ts *BackendTestSuite) TestMsgStatus() { ts.True(m.ModifiedOn_.After(now)) ts.True(m.SentOn_.After(now)) ts.Equal(null.NullString, m.FailedReason_) + ts.Equal(pq.StringArray([]string{string(clog1.UUID())}), m.LogUUIDs) sentOn := *m.SentOn_ // update to SENT using id - status = ts.b.NewMsgStatusForID(channel, courier.NewMsgID(10001), courier.MsgSent) + clog2 := courier.NewChannelLog(courier.ChannelLogTypeMsgStatus, channel) + status = ts.b.NewMsgStatusForID(channel, courier.NewMsgID(10001), courier.MsgSent, clog2) err = ts.b.WriteMsgStatus(ctx, status) ts.NoError(err) @@ -547,9 +551,11 @@ func (ts *BackendTestSuite) TestMsgStatus() { ts.Equal(null.String("ext0"), m.ExternalID_) // no change ts.True(m.ModifiedOn_.After(now)) ts.True(m.SentOn_.Equal(sentOn)) // no change + ts.Equal(pq.StringArray([]string{string(clog1.UUID()), string(clog2.UUID())}), m.LogUUIDs) // update to DELIVERED using id - status = ts.b.NewMsgStatusForID(channel, courier.NewMsgID(10001), courier.MsgDelivered) + clog3 := courier.NewChannelLog(courier.ChannelLogTypeMsgStatus, channel) + status = ts.b.NewMsgStatusForID(channel, courier.NewMsgID(10001), courier.MsgDelivered, clog3) err = ts.b.WriteMsgStatus(ctx, status) ts.NoError(err) time.Sleep(time.Second) @@ -558,9 +564,11 @@ func (ts *BackendTestSuite) TestMsgStatus() { ts.Equal(m.Status_, courier.MsgDelivered) ts.True(m.ModifiedOn_.After(now)) ts.True(m.SentOn_.Equal(sentOn)) // no change + ts.Equal(pq.StringArray([]string{string(clog1.UUID()), string(clog2.UUID()), string(clog3.UUID())}), m.LogUUIDs) // no change for incoming messages - status = ts.b.NewMsgStatusForID(channel, courier.NewMsgID(10002), courier.MsgSent) + clog4 := courier.NewChannelLog(courier.ChannelLogTypeMsgStatus, channel) + status = ts.b.NewMsgStatusForID(channel, courier.NewMsgID(10002), courier.MsgSent, clog4) err = ts.b.WriteMsgStatus(ctx, status) ts.NoError(err) @@ -569,9 +577,11 @@ func (ts *BackendTestSuite) TestMsgStatus() { m = readMsgFromDB(ts.b, courier.NewMsgID(10002)) ts.Equal(courier.MsgPending, m.Status_) ts.Equal(m.ExternalID_, null.String("ext2")) + ts.Equal(pq.StringArray(nil), m.LogUUIDs) // update to FAILED using external id - status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgFailed) + clog5 := courier.NewChannelLog(courier.ChannelLogTypeMsgStatus, channel) + status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgFailed, clog5) err = ts.b.WriteMsgStatus(ctx, status) ts.NoError(err) time.Sleep(time.Second) @@ -585,7 +595,8 @@ func (ts *BackendTestSuite) TestMsgStatus() { time.Sleep(2 * time.Millisecond) // update to WIRED using external id - status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgWired) + clog6 := courier.NewChannelLog(courier.ChannelLogTypeMsgStatus, channel) + status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgWired, clog6) err = ts.b.WriteMsgStatus(ctx, status) ts.NoError(err) @@ -599,7 +610,7 @@ func (ts *BackendTestSuite) TestMsgStatus() { sentOn = *m.SentOn_ // update to SENT using external id - status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgSent) + status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgSent, clog6) err = ts.b.WriteMsgStatus(ctx, status) ts.NoError(err) time.Sleep(time.Second) @@ -610,17 +621,17 @@ func (ts *BackendTestSuite) TestMsgStatus() { ts.True(m.SentOn_.Equal(sentOn)) // no change // no such external id for outgoing message - status = ts.b.NewMsgStatusForExternalID(channel, "ext2", courier.MsgSent) + status = ts.b.NewMsgStatusForExternalID(channel, "ext2", courier.MsgSent, clog6) err = ts.b.WriteMsgStatus(ctx, status) ts.Error(err) // no such external id - status = ts.b.NewMsgStatusForExternalID(channel, "ext3", courier.MsgSent) + status = ts.b.NewMsgStatusForExternalID(channel, "ext3", courier.MsgSent, clog6) err = ts.b.WriteMsgStatus(ctx, status) ts.Error(err) // reset our status to sent - status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgSent) + status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgSent, clog6) err = ts.b.WriteMsgStatus(ctx, status) ts.NoError(err) time.Sleep(time.Second) @@ -628,7 +639,7 @@ func (ts *BackendTestSuite) TestMsgStatus() { // error our msg now = time.Now().In(time.UTC) time.Sleep(2 * time.Millisecond) - status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgErrored) + status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgErrored, clog6) err = ts.b.WriteMsgStatus(ctx, status) ts.NoError(err) @@ -642,7 +653,7 @@ func (ts *BackendTestSuite) TestMsgStatus() { ts.Equal(null.NullString, m.FailedReason_) // second go - status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgErrored) + status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgErrored, clog6) err = ts.b.WriteMsgStatus(ctx, status) ts.NoError(err) @@ -654,7 +665,7 @@ func (ts *BackendTestSuite) TestMsgStatus() { ts.Equal(null.NullString, m.FailedReason_) // third go - status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgErrored) + status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgErrored, clog6) err = ts.b.WriteMsgStatus(ctx, status) time.Sleep(time.Second) // give committer time to write this @@ -673,7 +684,7 @@ func (ts *BackendTestSuite) TestMsgStatus() { ts.NoError(tx.Commit()) newURN, _ := urns.NewWhatsAppURN("5588776655") - status = ts.b.NewMsgStatusForID(channel, courier.MsgID(10000), courier.MsgSent) + status = ts.b.NewMsgStatusForID(channel, courier.MsgID(10000), courier.MsgSent, clog6) status.SetUpdatedURN(oldURN, newURN) ts.NoError(ts.b.WriteMsgStatus(ctx, status)) @@ -689,12 +700,12 @@ func (ts *BackendTestSuite) TestMsgStatus() { oldURN, _ = urns.NewWhatsAppURN("55999887766") newURN, _ = urns.NewWhatsAppURN("5599887766") tx, _ = ts.b.db.BeginTxx(ctx, nil) - contact, _ := contactForURN(ctx, ts.b, channel.OrgID_, channel, oldURN, "", "", clog) + contact, _ := contactForURN(ctx, ts.b, channel.OrgID_, channel, oldURN, "", "", clog6) _ = insertContactURN(tx, newDBContactURN(channel.OrgID_, channel.ID_, NilContactID, newURN, "")) ts.NoError(tx.Commit()) - status = ts.b.NewMsgStatusForID(channel, courier.MsgID(10007), courier.MsgSent) + status = ts.b.NewMsgStatusForID(channel, courier.MsgID(10007), courier.MsgSent, clog6) status.SetUpdatedURN(oldURN, newURN) ts.NoError(ts.b.WriteMsgStatus(ctx, status)) @@ -711,12 +722,12 @@ func (ts *BackendTestSuite) TestMsgStatus() { oldURN, _ = urns.NewWhatsAppURN("55988776655") newURN, _ = urns.NewWhatsAppURN("5588776655") tx, _ = ts.b.db.BeginTxx(ctx, nil) - _, _ = contactForURN(ctx, ts.b, channel.OrgID_, channel, oldURN, "", "", clog) - otherContact, _ := contactForURN(ctx, ts.b, channel.OrgID_, channel, newURN, "", "", clog) + _, _ = contactForURN(ctx, ts.b, channel.OrgID_, channel, oldURN, "", "", clog6) + otherContact, _ := contactForURN(ctx, ts.b, channel.OrgID_, channel, newURN, "", "", clog6) ts.NoError(tx.Commit()) - status = ts.b.NewMsgStatusForID(channel, courier.MsgID(10007), courier.MsgSent) + status = ts.b.NewMsgStatusForID(channel, courier.MsgID(10007), courier.MsgSent, clog6) status.SetUpdatedURN(oldURN, newURN) ts.NoError(ts.b.WriteMsgStatus(ctx, status)) @@ -859,6 +870,8 @@ func (ts *BackendTestSuite) TestOutgoingQueue() { ts.NoError(err) ts.NotNil(msg) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, msg.Channel()) + // make sure it is the message we just added ts.Equal(dbMsg.ID(), msg.ID()) @@ -866,7 +879,7 @@ func (ts *BackendTestSuite) TestOutgoingQueue() { ts.Equal(msg.Text(), "test message") // mark this message as dealt with - ts.b.MarkOutgoingMsgComplete(ctx, msg, ts.b.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgWired)) + ts.b.MarkOutgoingMsgComplete(ctx, msg, ts.b.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgWired, clog)) // this message should now be marked as sent sent, err := ts.b.WasMsgSent(ctx, msg.ID()) @@ -885,7 +898,7 @@ func (ts *BackendTestSuite) TestOutgoingQueue() { ts.False(sent) // write an error for our original message - err = ts.b.WriteMsgStatus(ctx, ts.b.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored)) + err = ts.b.WriteMsgStatus(ctx, ts.b.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog)) ts.NoError(err) // message should no longer be considered sent diff --git a/backends/rapidpro/status.go b/backends/rapidpro/status.go index 3a1517fc3..c4ebd920a 100644 --- a/backends/rapidpro/status.go +++ b/backends/rapidpro/status.go @@ -11,14 +11,13 @@ import ( "strconv" "time" - "github.com/nyaruka/gocommon/urns" - "github.com/jmoiron/sqlx" "github.com/nyaruka/courier" + "github.com/nyaruka/gocommon/urns" ) // newMsgStatus creates a new DBMsgStatus for the passed in parameters -func newMsgStatus(channel courier.Channel, id courier.MsgID, externalID string, status courier.MsgStatusValue) *DBMsgStatus { +func newMsgStatus(channel courier.Channel, id courier.MsgID, externalID string, status courier.MsgStatusValue, clog *courier.ChannelLog) *DBMsgStatus { dbChannel := channel.(*DBChannel) return &DBMsgStatus{ @@ -30,6 +29,7 @@ func newMsgStatus(channel courier.Channel, id courier.MsgID, externalID string, ExternalID_: externalID, Status_: status, ModifiedOn_: time.Now().In(time.UTC), + LogUUID: clog.UUID(), } } @@ -75,7 +75,7 @@ func checkMsgExists(b *backend, status courier.MsgStatus) (err error) { } // the craziness below lets us update our status to 'F' and schedule retries without knowing anything about the message -const updateMsgID = ` +const sqlUpdateMsgByID = ` UPDATE msgs_msg SET status = CASE WHEN @@ -131,7 +131,8 @@ UPDATE msgs_msg SET ELSE external_id END, - modified_on = :modified_on + modified_on = :modified_on, + log_uuids = array_append(log_uuids, :log_uuid) WHERE msgs_msg.id = :msg_id AND msgs_msg.channel_id = :channel_id AND @@ -140,7 +141,7 @@ RETURNING msgs_msg.id ` -const updateMsgExternalID = ` +const sqlUpdateMsgByExternalID = ` UPDATE msgs_msg SET status = CASE WHEN @@ -188,7 +189,8 @@ UPDATE msgs_msg SET ELSE NULL END, - modified_on = :modified_on + modified_on = :modified_on, + log_uuids = array_append(log_uuids, :log_uuid) WHERE msgs_msg.id = (SELECT msgs_msg.id FROM msgs_msg WHERE msgs_msg.external_id = :external_id AND msgs_msg.channel_id = :channel_id AND msgs_msg.direction = 'O' LIMIT 1) RETURNING @@ -201,9 +203,9 @@ func writeMsgStatusToDB(ctx context.Context, b *backend, status *DBMsgStatus) er var err error if status.ID() != courier.NilMsgID { - rows, err = b.db.NamedQueryContext(ctx, updateMsgID, status) + rows, err = b.db.NamedQueryContext(ctx, sqlUpdateMsgByID, status) } else if status.ExternalID() != "" { - rows, err = b.db.NamedQueryContext(ctx, updateMsgExternalID, status) + rows, err = b.db.NamedQueryContext(ctx, sqlUpdateMsgByExternalID, status) } else { return fmt.Errorf("attempt to update msg status without id or external id") } @@ -295,11 +297,12 @@ UPDATE msgs_msg SET ELSE msgs_msg.external_id END, - modified_on = NOW() + modified_on = NOW(), + log_uuids = array_append(log_uuids, s.log_uuid::uuid) FROM - (VALUES(:msg_id, :channel_id, :status, :external_id)) + (VALUES(:msg_id, :channel_id, :status, :external_id, :log_uuid)) AS - s(msg_id, channel_id, status, external_id) + s(msg_id, channel_id, status, external_id, log_uuid) WHERE msgs_msg.id = s.msg_id::bigint AND msgs_msg.channel_id = s.channel_id::int AND @@ -320,6 +323,7 @@ type DBMsgStatus struct { ExternalID_ string `json:"external_id,omitempty" db:"external_id"` Status_ courier.MsgStatusValue `json:"status" db:"status"` ModifiedOn_ time.Time `json:"modified_on" db:"modified_on"` + LogUUID courier.ChannelLogUUID `json:"log_uuid" db:"log_uuid"` } func (s *DBMsgStatus) EventID() int64 { return int64(s.ID_) } diff --git a/handler_test.go b/handler_test.go index 55f31516b..ac23440da 100644 --- a/handler_test.go +++ b/handler_test.go @@ -47,7 +47,7 @@ func (h *dummyHandler) Initialize(s courier.Server) error { // Send sends the given message, logging any HTTP calls or errors func (h *dummyHandler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { - return h.backend.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgSent), nil + return h.backend.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgSent, clog), nil } // ReceiveMsg sends the passed in message, returning any error diff --git a/handlers/africastalking/africastalking.go b/handlers/africastalking/africastalking.go index 86320a4df..ae134d03f 100644 --- a/handlers/africastalking/africastalking.go +++ b/handlers/africastalking/africastalking.go @@ -109,7 +109,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // write our status - status := h.Backend().NewMsgStatusForExternalID(channel, form.ID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(channel, form.ID, msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -128,7 +128,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no API key set for AT channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) // build our request form := url.Values{ diff --git a/handlers/arabiacell/arabiacell.go b/handlers/arabiacell/arabiacell.go index f1b12da15..43d2f0bdd 100644 --- a/handlers/arabiacell/arabiacell.go +++ b/handlers/arabiacell/arabiacell.go @@ -77,7 +77,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no charging_level set for AC channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) for _, part := range handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) { form := url.Values{ "userName": []string{username}, diff --git a/handlers/blackmyna/blackmyna.go b/handlers/blackmyna/blackmyna.go index d70b2dd99..0bcaa7377 100644 --- a/handlers/blackmyna/blackmyna.go +++ b/handlers/blackmyna/blackmyna.go @@ -90,7 +90,7 @@ func (h *handler) StatusMessage(ctx context.Context, channel courier.Channel, w } // write our status - status := h.Backend().NewMsgStatusForExternalID(channel, form.ID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(channel, form.ID, msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -111,7 +111,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no API key set for BM channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) // build our request form := url.Values{ diff --git a/handlers/bongolive/bongolive.go b/handlers/bongolive/bongolive.go index d1ad22cc1..c1cea888d 100644 --- a/handlers/bongolive/bongolive.go +++ b/handlers/bongolive/bongolive.go @@ -83,7 +83,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // write our status - status := h.Backend().NewMsgStatusForExternalID(channel, form.DLRID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(channel, form.DLRID, msgStatus, clog) err = h.Backend().WriteMsgStatus(ctx, status) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) @@ -135,7 +135,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no password set for %s channel", msg.Channel().ChannelType()) } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) for _, part := range parts { form := url.Values{ diff --git a/handlers/burstsms/burstsms.go b/handlers/burstsms/burstsms.go index 3c4b8c1fb..c8b7cb4e9 100644 --- a/handlers/burstsms/burstsms.go +++ b/handlers/burstsms/burstsms.go @@ -67,7 +67,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no password set for BS channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) for _, part := range handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) { form := url.Values{ "to": []string{strings.TrimLeft(msg.URN().Path(), "+")}, diff --git a/handlers/chikka/chikka.go b/handlers/chikka/chikka.go index 4de7c2f41..82f53c5ae 100644 --- a/handlers/chikka/chikka.go +++ b/handlers/chikka/chikka.go @@ -76,7 +76,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // write our status - status := h.Backend().NewMsgStatusForID(channel, courier.NewMsgID(form.MessageID), msgStatus) + status := h.Backend().NewMsgStatusForID(channel, courier.NewMsgID(form.MessageID), msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } else if messageType == "incoming" { @@ -115,7 +115,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no password set for CK channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) for _, part := range parts { // build our request diff --git a/handlers/clickatell/clickatell.go b/handlers/clickatell/clickatell.go index 5f6cc6078..6e5ea76a7 100644 --- a/handlers/clickatell/clickatell.go +++ b/handlers/clickatell/clickatell.go @@ -85,7 +85,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // write our status - status := h.Backend().NewMsgStatusForExternalID(channel, payload.MessageID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(channel, payload.MessageID, msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -175,7 +175,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no api_key set for CT channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) for _, part := range parts { form := url.Values{ diff --git a/handlers/clickmobile/clickmobile.go b/handlers/clickmobile/clickmobile.go index 8f51b6059..d59e2bf05 100644 --- a/handlers/clickmobile/clickmobile.go +++ b/handlers/clickmobile/clickmobile.go @@ -121,7 +121,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann cmSendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, sendURL) - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) for _, part := range handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) { diff --git a/handlers/clicksend/clicksend.go b/handlers/clicksend/clicksend.go index 824c3e0aa..dfca3593d 100644 --- a/handlers/clicksend/clicksend.go +++ b/handlers/clicksend/clicksend.go @@ -72,7 +72,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("Missing 'password' config for CS channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) for _, part := range parts { payload := &mtPayload{} diff --git a/handlers/dart/dart.go b/handlers/dart/dart.go index b1a4bd9fc..07b07ff6d 100644 --- a/handlers/dart/dart.go +++ b/handlers/dart/dart.go @@ -120,7 +120,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // write our status - status := h.Backend().NewMsgStatusForID(channel, courier.NewMsgID(msgID), msgStatus) + status := h.Backend().NewMsgStatusForID(channel, courier.NewMsgID(msgID), msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -150,7 +150,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no password set for %s channel", msg.Channel().ChannelType()) } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), h.maxLength) for i, part := range parts { form := url.Values{ diff --git a/handlers/discord/discord.go b/handlers/discord/discord.go index 022fe23f4..d7f2b2d36 100644 --- a/handlers/discord/discord.go +++ b/handlers/discord/discord.go @@ -149,7 +149,7 @@ func (h *handler) receiveStatus(ctx context.Context, statusString string, channe } // write our status - status := h.Backend().NewMsgStatusForID(channel, courier.NewMsgID(form.ID), msgStatus) + status := h.Backend().NewMsgStatusForID(channel, courier.NewMsgID(form.ID), msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -165,7 +165,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // sendBody := msg.Channel().StringConfigForKey(courier.ConfigSendBody, "") contentTypeHeader := jsonMimeTypeType - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) attachmentURLs := []string{} for _, attachment := range msg.Attachments() { _, attachmentURL := handlers.SplitAttachment(attachment) diff --git a/handlers/dmark/dmark.go b/handlers/dmark/dmark.go index f56ac1c65..092bd20e9 100644 --- a/handlers/dmark/dmark.go +++ b/handlers/dmark/dmark.go @@ -102,7 +102,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // write our status - status := h.Backend().NewMsgStatusForExternalID(channel, form.ID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(channel, form.ID, msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -117,7 +117,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann callbackDomain := msg.Channel().CallbackDomain(h.Server().Config().Domain) dlrURL := fmt.Sprintf("https://%s%s%s/status?id=%s&status=%%s", callbackDomain, "/c/dk/", msg.Channel().UUID(), msg.ID().String()) - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), msg.Text(), maxMsgLength) for i, part := range parts { form := url.Values{ diff --git a/handlers/external/external.go b/handlers/external/external.go index 92f9f6761..fdaf94537 100644 --- a/handlers/external/external.go +++ b/handlers/external/external.go @@ -267,7 +267,7 @@ func (h *handler) receiveStatus(ctx context.Context, statusString string, channe } // write our status - status := h.Backend().NewMsgStatusForID(channel, courier.NewMsgID(form.ID), msgStatus) + status := h.Backend().NewMsgStatusForID(channel, courier.NewMsgID(form.ID), msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -289,7 +289,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann contentTypeHeader = contentType } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), 160) for i, part := range parts { // build our request diff --git a/handlers/facebook/facebook.go b/handlers/facebook/facebook.go index 17705f379..be91408d3 100644 --- a/handlers/facebook/facebook.go +++ b/handlers/facebook/facebook.go @@ -412,7 +412,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } else if msg.Delivery != nil { // this is a delivery report for _, mid := range msg.Delivery.MIDs { - event := h.Backend().NewMsgStatusForExternalID(channel, mid, courier.MsgDelivered) + event := h.Backend().NewMsgStatusForExternalID(channel, mid, courier.MsgDelivered, clog) err := h.Backend().WriteMsgStatus(ctx, event) // we don't know about this message, just tell them we ignored it @@ -513,7 +513,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann query.Set("access_token", accessToken) msgURL.RawQuery = query.Encode() - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) msgParts := make([]string, 0) if msg.Text() != "" { diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 9eb53e9f9..3dd2156fd 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -499,7 +499,7 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri continue } - event := h.Backend().NewMsgStatusForExternalID(channel, status.ID, msgStatus) + event := h.Backend().NewMsgStatusForExternalID(channel, status.ID, msgStatus, clog) err := h.Backend().WriteMsgStatus(ctx, event) // we don't know about this message, just tell them we ignored it @@ -734,7 +734,7 @@ func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel c } else if msg.Delivery != nil { // this is a delivery report for _, mid := range msg.Delivery.MIDs { - event := h.Backend().NewMsgStatusForExternalID(channel, mid, courier.MsgDelivered) + event := h.Backend().NewMsgStatusForExternalID(channel, mid, courier.MsgDelivered, clog) err := h.Backend().WriteMsgStatus(ctx, event) // we don't know about this message, just tell them we ignored it @@ -845,7 +845,7 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, query.Set("access_token", accessToken) msgURL.RawQuery = query.Encode() - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) msgParts := make([]string, 0) if msg.Text() != "" { @@ -1063,7 +1063,7 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, path, _ := url.Parse(fmt.Sprintf("/%s/messages", msg.Channel().Address())) wacPhoneURL := base.ResolveReference(path) - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) hasCaption := false diff --git a/handlers/firebase/firebase.go b/handlers/firebase/firebase.go index a11fc21e0..a02fce59e 100644 --- a/handlers/firebase/firebase.go +++ b/handlers/firebase/firebase.go @@ -154,7 +154,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann msgParts = handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) for i, part := range msgParts { payload := mtPayload{} diff --git a/handlers/freshchat/freshchat.go b/handlers/freshchat/freshchat.go index 841ecefea..3cc009555 100644 --- a/handlers/freshchat/freshchat.go +++ b/handlers/freshchat/freshchat.go @@ -114,7 +114,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } user := strings.Split(msg.URN().Path(), "/") - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) url := apiURL + "/conversations" // create base payload diff --git a/handlers/generic.go b/handlers/generic.go index 6e8b648ec..cd774afe7 100644 --- a/handlers/generic.go +++ b/handlers/generic.go @@ -53,7 +53,7 @@ func NewExternalIDStatusHandler(h *BaseHandler, statuses map[string]courier.MsgS } // create our status - status := h.Backend().NewMsgStatusForExternalID(c, externalID, sValue) + status := h.Backend().NewMsgStatusForExternalID(c, externalID, sValue, clog) return WriteMsgStatusAndResponse(ctx, h, c, status, w, r) } } diff --git a/handlers/globe/globe.go b/handlers/globe/globe.go index 71c23592c..f08e55d4f 100644 --- a/handlers/globe/globe.go +++ b/handlers/globe/globe.go @@ -142,7 +142,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("Missing 'passphrase' config for GL channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) for _, part := range parts { payload := &mtPayload{} diff --git a/handlers/highconnection/highconnection.go b/handlers/highconnection/highconnection.go index 2f994c17c..8c88021df 100644 --- a/handlers/highconnection/highconnection.go +++ b/handlers/highconnection/highconnection.go @@ -111,7 +111,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // write our status - status := h.Backend().NewMsgStatusForID(channel, courier.NewMsgID(form.RetID), msgStatus) + status := h.Backend().NewMsgStatusForID(channel, courier.NewMsgID(form.RetID), msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -131,7 +131,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann statusURL := fmt.Sprintf("https://%s/c/hx/%s/status", callbackDomain, msg.Channel().UUID()) receiveURL := fmt.Sprintf("https://%s/c/hx/%s/receive", callbackDomain, msg.Channel().UUID()) - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) for _, part := range parts { diff --git a/handlers/hormuud/hormuud.go b/handlers/hormuud/hormuud.go index 476670637..40d5806f7 100644 --- a/handlers/hormuud/hormuud.go +++ b/handlers/hormuud/hormuud.go @@ -81,7 +81,7 @@ type mtPayload struct { // Send sends the given message, logging any HTTP calls or errors func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) token, err := h.FetchToken(ctx, msg.Channel(), msg, clog) if err != nil { diff --git a/handlers/i2sms/i2sms.go b/handlers/i2sms/i2sms.go index 4d8843d3c..ae1e3824d 100644 --- a/handlers/i2sms/i2sms.go +++ b/handlers/i2sms/i2sms.go @@ -99,7 +99,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no channel_hash set for I2 channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) for _, part := range handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) { form := url.Values{ "action": []string{"send_single"}, diff --git a/handlers/infobip/infobip.go b/handlers/infobip/infobip.go index 4f1a68360..de56bb9a0 100644 --- a/handlers/infobip/infobip.go +++ b/handlers/infobip/infobip.go @@ -74,7 +74,7 @@ func (h *handler) statusMessage(ctx context.Context, channel courier.Channel, w } // write our status - status := h.Backend().NewMsgStatusForExternalID(channel, s.MessageID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(channel, s.MessageID, msgStatus, clog) err = h.Backend().WriteMsgStatus(ctx, status) if err == courier.ErrMsgNotFound { data = append(data, courier.NewInfoData(fmt.Sprintf("ignoring status update message id: %s, not found", s.MessageID))) @@ -225,7 +225,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann req.Header.Set("Accept", "application/json") req.SetBasicAuth(username, password) - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { diff --git a/handlers/jasmin/jasmin.go b/handlers/jasmin/jasmin.go index 851e828cb..7d2077212 100644 --- a/handlers/jasmin/jasmin.go +++ b/handlers/jasmin/jasmin.go @@ -60,7 +60,7 @@ func (h *handler) receiveStatus(ctx context.Context, c courier.Channel, w http.R return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, fmt.Errorf("must have either dlvrd or err set to 1")) } - status := h.Backend().NewMsgStatusForExternalID(c, form.ID, reqStatus) + status := h.Backend().NewMsgStatusForExternalID(c, form.ID, reqStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, c, status, w, r) } @@ -160,7 +160,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, err } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index ea8b7422f..fe64bf7fc 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -240,7 +240,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, err } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) for _, part := range parts { jcMsg := &mtPayload{} diff --git a/handlers/junebug/junebug.go b/handlers/junebug/junebug.go index 545868ba9..468258acd 100644 --- a/handlers/junebug/junebug.go +++ b/handlers/junebug/junebug.go @@ -135,7 +135,7 @@ func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.Re return nil, handlers.WriteAndLogRequestIgnored(ctx, h, c, w, r, "ignoring existing pending status") } - status := h.Backend().NewMsgStatusForExternalID(c, payload.MessageID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(c, payload.MessageID, msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, c, status, w, r) } @@ -171,7 +171,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann callbackDomain := msg.Channel().CallbackDomain(h.Server().Config().Domain) eventURL := fmt.Sprintf("https://%s/c/jn/%s/event", callbackDomain, msg.Channel().UUID()) - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) for i, part := range handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) { payload := mtPayload{ EventURL: eventURL, diff --git a/handlers/kaleyra/kaleyra.go b/handlers/kaleyra/kaleyra.go index 7a1f56c11..e3e9b0f1b 100644 --- a/handlers/kaleyra/kaleyra.go +++ b/handlers/kaleyra/kaleyra.go @@ -127,7 +127,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // msg not found? ignore this - status := h.Backend().NewMsgStatusForExternalID(channel, form.ID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(channel, form.ID, msgStatus, clog) if status == nil { return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, fmt.Sprintf("ignoring request, message %s not found", form.ID)) } @@ -145,7 +145,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, errors.New("no account_sid or api_key config") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) sendURL := fmt.Sprintf("%s/v1/%s/messages", baseURL, accountSID) var kwaResp *http.Response diff --git a/handlers/kannel/kannel.go b/handlers/kannel/kannel.go index 861cb04f1..81e7f4cec 100644 --- a/handlers/kannel/kannel.go +++ b/handlers/kannel/kannel.go @@ -113,7 +113,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // write our status - status := h.Backend().NewMsgStatusForID(channel, form.ID, msgStatus) + status := h.Backend().NewMsgStatusForID(channel, form.ID, msgStatus, clog) err = h.Backend().WriteMsgStatus(ctx, status) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -207,7 +207,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann resp, _, err = handlers.RequestHTTPInsecure(req, clog) } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) if err == nil && resp.StatusCode/100 == 2 { status.SetStatus(courier.MsgWired) } diff --git a/handlers/line/line.go b/handlers/line/line.go index 909ac6a7b..3320e1ea4 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -288,7 +288,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann if authToken == "" { return nil, fmt.Errorf("no auth token set for LN channel: %s", msg.Channel().UUID()) } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) // all msg parts in JSON var jsonMsgs []string diff --git a/handlers/m3tech/m3tech.go b/handlers/m3tech/m3tech.go index ce178ccd3..af93d1f2b 100644 --- a/handlers/m3tech/m3tech.go +++ b/handlers/m3tech/m3tech.go @@ -88,7 +88,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } // send our message - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) for _, part := range handlers.SplitMsgByChannel(msg.Channel(), text, maxMsgLength) { // build our request params := url.Values{ diff --git a/handlers/macrokiosk/macrokiosk.go b/handlers/macrokiosk/macrokiosk.go index 74c9244cf..3561056e2 100644 --- a/handlers/macrokiosk/macrokiosk.go +++ b/handlers/macrokiosk/macrokiosk.go @@ -73,7 +73,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, fmt.Sprintf("ignoring unknown status '%s'", form.Status)) } // write our status - status := h.Backend().NewMsgStatusForExternalID(channel, form.MsgID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(channel, form.MsgID, msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -168,7 +168,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann encoding = "5" } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), text, maxMsgLength) for i, part := range parts { payload := &mtPayload{ diff --git a/handlers/mblox/mblox.go b/handlers/mblox/mblox.go index 220e50e9a..2ed5ee1a1 100644 --- a/handlers/mblox/mblox.go +++ b/handlers/mblox/mblox.go @@ -78,7 +78,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } // write our status - status := h.Backend().NewMsgStatusForExternalID(channel, payload.BatchID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(channel, payload.BatchID, msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } else if payload.Type == "mo_text" { @@ -122,7 +122,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("Missing username or password for MB channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) for _, part := range parts { payload := &mtPayload{} diff --git a/handlers/messangi/messangi.go b/handlers/messangi/messangi.go index bf41cf78e..e74c52787 100644 --- a/handlers/messangi/messangi.go +++ b/handlers/messangi/messangi.go @@ -81,7 +81,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no carrier_id set for MG channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) for _, part := range parts { shortcode := strings.TrimPrefix(msg.Channel().Address(), "+") diff --git a/handlers/mtarget/mtarget.go b/handlers/mtarget/mtarget.go index 3b87e060f..905f4166b 100644 --- a/handlers/mtarget/mtarget.go +++ b/handlers/mtarget/mtarget.go @@ -160,7 +160,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } // send our message - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) for _, part := range handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) { // build our request params := url.Values{ diff --git a/handlers/nexmo/nexmo.go b/handlers/nexmo/nexmo.go index 716fc6454..8d164c80e 100644 --- a/handlers/nexmo/nexmo.go +++ b/handlers/nexmo/nexmo.go @@ -83,7 +83,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring unknown status report") } - status := h.Backend().NewMsgStatusForExternalID(channel, form.MessageID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(channel, form.MessageID, msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -138,7 +138,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann textType = "unicode" } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), text, maxMsgLength) for _, part := range parts { form := url.Values{ diff --git a/handlers/novo/novo.go b/handlers/novo/novo.go index afe61a9a2..3c1c5468f 100644 --- a/handlers/novo/novo.go +++ b/handlers/novo/novo.go @@ -89,7 +89,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no merchant_secret set for NV channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) for _, part := range parts { from := strings.TrimPrefix(msg.Channel().Address(), "+") diff --git a/handlers/playmobile/playmobile.go b/handlers/playmobile/playmobile.go index b32bb0ac3..4ebf912b2 100644 --- a/handlers/playmobile/playmobile.go +++ b/handlers/playmobile/playmobile.go @@ -166,7 +166,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no base url set for PM channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) for i, part := range handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) { payload := mtPayload{} diff --git a/handlers/plivo/plivo.go b/handlers/plivo/plivo.go index bb1ec18e9..e443eb7dc 100644 --- a/handlers/plivo/plivo.go +++ b/handlers/plivo/plivo.go @@ -92,7 +92,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // write our status - status := h.Backend().NewMsgStatusForExternalID(channel, externalID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(channel, externalID, msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -147,7 +147,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann callbackDomain := msg.Channel().CallbackDomain(h.Server().Config().Domain) statusURL := fmt.Sprintf("https://%s/c/pl/%s/status", callbackDomain, msg.Channel().UUID()) - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) for i, part := range parts { payload := &mtPayload{ diff --git a/handlers/redrabbit/redrabbit.go b/handlers/redrabbit/redrabbit.go index c31d9a3b9..59bfc586b 100644 --- a/handlers/redrabbit/redrabbit.go +++ b/handlers/redrabbit/redrabbit.go @@ -44,7 +44,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } text := handlers.GetTextAndAttachments(msg) - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) form := url.Values{ "LoginName": []string{username}, "Password": []string{password}, diff --git a/handlers/rocketchat/rocketchat.go b/handlers/rocketchat/rocketchat.go index ab6352e0e..56ecd168f 100644 --- a/handlers/rocketchat/rocketchat.go +++ b/handlers/rocketchat/rocketchat.go @@ -115,7 +115,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann botUsername := msg.Channel().StringConfigForKey(configBotUsername, "") // the status that will be written for this message - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) payload := &mtPayload{ UserURN: msg.URN().Path(), diff --git a/handlers/shaqodoon/shaqodoon.go b/handlers/shaqodoon/shaqodoon.go index eb0b62bce..d06fb1910 100644 --- a/handlers/shaqodoon/shaqodoon.go +++ b/handlers/shaqodoon/shaqodoon.go @@ -114,7 +114,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) resp, _, err := handlers.RequestHTTPInsecure(req, clog) if err != nil || resp.StatusCode/100 != 2 { diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index ce0adfcdc..52b42c947 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -154,7 +154,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("missing bot token for SL/slack channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) for _, attachment := range msg.Attachments() { fileAttachment, err := parseAttachmentToFileParams(msg, attachment, clog) diff --git a/handlers/smscentral/smscentral.go b/handlers/smscentral/smscentral.go index a90e22f81..e0cc05eb1 100644 --- a/handlers/smscentral/smscentral.go +++ b/handlers/smscentral/smscentral.go @@ -74,7 +74,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no password set for SC channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) // build our request form := url.Values{ diff --git a/handlers/start/start.go b/handlers/start/start.go index 46f81369d..a4157788b 100644 --- a/handlers/start/start.go +++ b/handlers/start/start.go @@ -131,7 +131,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no password set for ST channel: %s", msg.Channel().UUID()) } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) for i, part := range parts { diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index e8f2240ea..047a719ac 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -203,7 +203,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } // the status that will be written for this message - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) // whether we encountered any errors sending any parts hasError := true diff --git a/handlers/telesom/telesom.go b/handlers/telesom/telesom.go index 58b6b50e8..2f54ad964 100644 --- a/handlers/telesom/telesom.go +++ b/handlers/telesom/telesom.go @@ -83,7 +83,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann tsSendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, sendURL) - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) for _, part := range handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) { from := strings.TrimPrefix(msg.Channel().Address(), "+") diff --git a/handlers/thinq/thinq.go b/handlers/thinq/thinq.go index 6d2940ebf..99f0a7a90 100644 --- a/handlers/thinq/thinq.go +++ b/handlers/thinq/thinq.go @@ -124,7 +124,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // write our status - status := h.Backend().NewMsgStatusForExternalID(channel, form.GUID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(channel, form.GUID, msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -151,7 +151,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no token set for TQ channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) // we send attachments first so that text appears below for _, a := range msg.Attachments() { diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index 800eb0c99..df39417cb 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -171,13 +171,13 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w if err != nil { logrus.WithError(err).WithField("id", idString).Error("error converting twilio callback id to integer") } else { - status = h.Backend().NewMsgStatusForID(channel, courier.NewMsgID(msgID), msgStatus) + status = h.Backend().NewMsgStatusForID(channel, courier.NewMsgID(msgID), msgStatus, clog) } } // if we have no status, then build it from the external (twilio) id if status == nil { - status = h.Backend().NewMsgStatusForExternalID(channel, form.MessageSID, msgStatus) + status = h.Backend().NewMsgStatusForExternalID(channel, form.MessageSID, msgStatus, clog) } errorCode, _ := strconv.ParseInt(form.ErrorCode, 10, 64) @@ -217,7 +217,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann channel := msg.Channel() - status := h.Backend().NewMsgStatusForID(channel, msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(channel, msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), msg.Text(), maxMsgLength) for i, part := range parts { // build our request diff --git a/handlers/twitter/twitter.go b/handlers/twitter/twitter.go index 2875a98ea..7869750b0 100644 --- a/handlers/twitter/twitter.go +++ b/handlers/twitter/twitter.go @@ -269,7 +269,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann token := oauth1.NewToken(accessToken, accessSecret) client := config.Client(ctx, token) - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) // we build these as needed since our unit tests manipulate apiURL sendURL := sendDomain + "/1.1/direct_messages/events/new.json" diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index b1c44abf6..7155583a2 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -169,7 +169,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(ctx, w, r, channelEvent) case "failed": - msgStatus := h.Backend().NewMsgStatusForExternalID(channel, fmt.Sprintf("%d", payload.MessageToken), courier.MsgFailed) + msgStatus := h.Backend().NewMsgStatusForExternalID(channel, fmt.Sprintf("%d", payload.MessageToken), courier.MsgFailed, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, msgStatus, w, r) case "delivered": @@ -315,7 +315,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("missing auth token in config") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) // figure out whether we have a keyboard to send as well qrs := msg.QuickReplies() diff --git a/handlers/vk/vk.go b/handlers/vk/vk.go index 43c90b3cf..e6bb15c58 100644 --- a/handlers/vk/vk.go +++ b/handlers/vk/vk.go @@ -386,7 +386,7 @@ func takeFirstAttachmentUrl(payload moNewMessagePayload) string { } func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) params := buildApiBaseParams(msg.Channel()) params.Set(paramUserId, msg.URN().Path()) diff --git a/handlers/wavy/wavy.go b/handlers/wavy/wavy.go index 474887502..2c061e413 100644 --- a/handlers/wavy/wavy.go +++ b/handlers/wavy/wavy.go @@ -75,7 +75,7 @@ func (h *handler) sentStatusMessage(ctx context.Context, channel courier.Channel } // write our status - status := h.Backend().NewMsgStatusForExternalID(channel, payload.CollerationID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(channel, payload.CollerationID, msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -98,7 +98,7 @@ func (h *handler) deliveredStatusMessage(ctx context.Context, channel courier.Ch } // write our status - status := h.Backend().NewMsgStatusForExternalID(channel, payload.CollerationID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(channel, payload.CollerationID, msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -150,7 +150,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no token set for %s channel", msg.Channel().ChannelType()) } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) payload := mtPayload{} payload.Destination = strings.TrimPrefix(msg.URN().Path(), "+") diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index c2b37a5a2..c1ed10df4 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -248,7 +248,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann partSendURL, _ := url.Parse(fmt.Sprintf("%s/%s", sendURL, "message/custom/send")) partSendURL.RawQuery = form.Encode() - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) for _, part := range parts { wcMsg := &mtPayload{} diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index 7de47a483..1a35f1680 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -273,7 +273,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h continue } - event := h.Backend().NewMsgStatusForExternalID(channel, status.ID, msgStatus) + event := h.Backend().NewMsgStatusForExternalID(channel, status.ID, msgStatus, clog) err := h.Backend().WriteMsgStatus(ctx, event) // we don't know about this message, just tell them we ignored it @@ -513,7 +513,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } sendPath, _ := url.Parse("/v1/messages") - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) var wppID string diff --git a/handlers/yo/yo.go b/handlers/yo/yo.go index d6b88ee57..502bba98f 100644 --- a/handlers/yo/yo.go +++ b/handlers/yo/yo.go @@ -108,7 +108,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no password set for YO channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) var err error for _, part := range handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) { diff --git a/handlers/zenvia/zenvia.go b/handlers/zenvia/zenvia.go index 2514cb9c3..c5c886a64 100644 --- a/handlers/zenvia/zenvia.go +++ b/handlers/zenvia/zenvia.go @@ -174,7 +174,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // write our status - status := h.Backend().NewMsgStatusForExternalID(channel, payload.MessageID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(channel, payload.MessageID, msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -207,7 +207,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann To: strings.TrimLeft(msg.URN().Path(), "+"), } - status := h.Backend().NewMsgStatusForID(channel, msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(channel, msg.ID(), courier.MsgErrored, clog) text := "" if channel.ChannelType() == "ZVW" { diff --git a/handlers/zenviaold/zenviaold.go b/handlers/zenviaold/zenviaold.go index 602029544..afeec2f8c 100644 --- a/handlers/zenviaold/zenviaold.go +++ b/handlers/zenviaold/zenviaold.go @@ -157,7 +157,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // write our status - status := h.Backend().NewMsgStatusForExternalID(channel, payload.CallbackMTRequest.ID, msgStatus) + status := h.Backend().NewMsgStatusForExternalID(channel, payload.CallbackMTRequest.ID, msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } @@ -174,7 +174,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("no password set for ZV channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) for _, part := range parts { zvMsg := mtPayload{} diff --git a/sender.go b/sender.go index 4cf2a1a96..b1182355b 100644 --- a/sender.go +++ b/sender.go @@ -193,7 +193,7 @@ func (w *Sender) sendMessage(msg Msg) { if sent { // if this message was already sent, create a wired status for it - status = backend.NewMsgStatusForID(msg.Channel(), msg.ID(), MsgWired) + status = backend.NewMsgStatusForID(msg.Channel(), msg.ID(), MsgWired, clog) log.Warning("duplicate send, marking as wired") } else { // send our message @@ -207,7 +207,7 @@ func (w *Sender) sendMessage(msg Msg) { // possible for handlers to only return an error in which case we construct an error status if status == nil { - status = backend.NewMsgStatusForID(msg.Channel(), msg.ID(), MsgErrored) + status = backend.NewMsgStatusForID(msg.Channel(), msg.ID(), MsgErrored, clog) } } diff --git a/test/backend.go b/test/backend.go index d2772c470..1ad786e76 100644 --- a/test/backend.go +++ b/test/backend.go @@ -211,7 +211,7 @@ func (mb *MockBackend) WriteMsg(ctx context.Context, m courier.Msg, clog *courie } // NewMsgStatusForID creates a new Status object for the given message id -func (mb *MockBackend) NewMsgStatusForID(channel courier.Channel, id courier.MsgID, status courier.MsgStatusValue) courier.MsgStatus { +func (mb *MockBackend) NewMsgStatusForID(channel courier.Channel, id courier.MsgID, status courier.MsgStatusValue, clog *courier.ChannelLog) courier.MsgStatus { return &mockMsgStatus{ channel: channel, id: id, @@ -221,7 +221,7 @@ func (mb *MockBackend) NewMsgStatusForID(channel courier.Channel, id courier.Msg } // NewMsgStatusForExternalID creates a new Status object for the given external id -func (mb *MockBackend) NewMsgStatusForExternalID(channel courier.Channel, externalID string, status courier.MsgStatusValue) courier.MsgStatus { +func (mb *MockBackend) NewMsgStatusForExternalID(channel courier.Channel, externalID string, status courier.MsgStatusValue, clog *courier.ChannelLog) courier.MsgStatus { return &mockMsgStatus{ channel: channel, externalID: externalID, From 2a0f15fddea6d69a0e9fe9afea44d9f90930e300 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 7 Sep 2022 14:24:20 -0500 Subject: [PATCH 141/294] Remove unused support for creating outgoing messages --- backends/rapidpro/backend.go | 7 +------ backends/rapidpro/backend_test.go | 3 ++- backends/rapidpro/msg.go | 7 +------ backends/rapidpro/status.go | 2 +- 4 files changed, 5 insertions(+), 14 deletions(-) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index fed8f9c2f..0356cd849 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -38,7 +38,7 @@ const msgQueueName = "msgs" const sentSetName = "msgs_sent_%s" // our timeout for backend operations -const backendTimeout = time.Second * 2000 +const backendTimeout = time.Second * 20 var uuidRegex = regexp.MustCompile(`[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`) @@ -151,11 +151,6 @@ func (b *backend) NewIncomingMsg(channel courier.Channel, urn urns.URN, text str return msg } -// NewOutgoingMsg creates a new outgoing message from the given params -func (b *backend) NewOutgoingMsg(channel courier.Channel, urn urns.URN, text string) courier.Msg { - return newMsg(MsgOutgoing, channel, urn, text, nil) -} - // PopNextOutgoingMsg pops the next message that needs to be sent func (b *backend) PopNextOutgoingMsg(ctx context.Context) (courier.Msg, error) { // pop the next message off our queue diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 98a34bd08..7716cf42a 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -810,9 +810,10 @@ func (ts *BackendTestSuite) TestExternalIDDupes() { defer r.Close() knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel) urn, _ := urns.NewTelURNForCountry("12065551215", knChannel.Country()) - msg := newMsg(MsgIncoming, knChannel, urn, "ping", nil) + msg := newMsg(MsgIncoming, knChannel, urn, "ping", clog) var checkedMsg = ts.b.CheckExternalIDSeen(msg) m := checkedMsg.(*DBMsg) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index 5661bc18e..1dddcbac3 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -118,11 +118,6 @@ func newMsg(direction MsgDirection, channel courier.Channel, urn urns.URN, text now := time.Now() dbChannel := channel.(*DBChannel) - var logUUIDs []string - if clog != nil { - logUUIDs = []string{string(clog.UUID())} - } - return &DBMsg{ OrgID_: dbChannel.OrgID(), UUID_: courier.NewMsgUUID(), @@ -142,7 +137,7 @@ func newMsg(direction MsgDirection, channel courier.Channel, urn urns.URN, text CreatedOn_: now, ModifiedOn_: now, QueuedOn_: now, - LogUUIDs: logUUIDs, + LogUUIDs: []string{string(clog.UUID())}, channel: dbChannel, workerToken: "", diff --git a/backends/rapidpro/status.go b/backends/rapidpro/status.go index c4ebd920a..ed78aed26 100644 --- a/backends/rapidpro/status.go +++ b/backends/rapidpro/status.go @@ -323,7 +323,7 @@ type DBMsgStatus struct { ExternalID_ string `json:"external_id,omitempty" db:"external_id"` Status_ courier.MsgStatusValue `json:"status" db:"status"` ModifiedOn_ time.Time `json:"modified_on" db:"modified_on"` - LogUUID courier.ChannelLogUUID `json:"log_uuid" db:"log_uuid"` + LogUUID courier.ChannelLogUUID `json:"log_uuid" db:"log_uuid"` } func (s *DBMsgStatus) EventID() int64 { return int64(s.ID_) } From 61754fba26f244e17b8cf9b28653f75791e6d01c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 7 Sep 2022 14:57:56 -0500 Subject: [PATCH 142/294] Remove duplicate status writes --- handlers/bongolive/bongolive.go | 2 -- handlers/kannel/kannel.go | 1 - 2 files changed, 3 deletions(-) diff --git a/handlers/bongolive/bongolive.go b/handlers/bongolive/bongolive.go index c1cea888d..826b303a9 100644 --- a/handlers/bongolive/bongolive.go +++ b/handlers/bongolive/bongolive.go @@ -84,9 +84,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w // write our status status := h.Backend().NewMsgStatusForExternalID(channel, form.DLRID, msgStatus, clog) - err = h.Backend().WriteMsgStatus(ctx, status) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) - } // create our URN diff --git a/handlers/kannel/kannel.go b/handlers/kannel/kannel.go index 81e7f4cec..92db7accf 100644 --- a/handlers/kannel/kannel.go +++ b/handlers/kannel/kannel.go @@ -114,7 +114,6 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w // write our status status := h.Backend().NewMsgStatusForID(channel, form.ID, msgStatus, clog) - err = h.Backend().WriteMsgStatus(ctx, status) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) } From 2352f90ee7517b016d1961d6da740f9ca3a04710 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 7 Sep 2022 17:16:20 -0500 Subject: [PATCH 143/294] Rework handler tests to assert more state by default --- handler_test.go | 4 +- .../africastalking/africastalking_test.go | 2 + handlers/blackmyna/blackmyna_test.go | 1 + handlers/bongolive/bongolive_test.go | 1 + handlers/chikka/chikka_test.go | 2 + handlers/clickatell/clickatell_test.go | 2 + handlers/discord/discord_test.go | 1 + handlers/dmark/dmark_test.go | 7 +- handlers/external/external_test.go | 15 +- handlers/facebook/facebook_test.go | 3 +- handlers/facebookapp/facebookapp_test.go | 1 - .../highconnection/highconnection_test.go | 1 + handlers/infobip/infobip_test.go | 8 +- handlers/jiochat/jiochat_test.go | 29 +++- handlers/kaleyra/kaleyra_test.go | 3 - handlers/kannel/kannel_test.go | 4 +- handlers/macrokiosk/macrokiosk_test.go | 4 +- handlers/mblox/mblox_test.go | 2 +- handlers/nexmo/nexmo_test.go | 108 ++++++++++---- handlers/plivo/plivo_test.go | 4 +- handlers/test.go | 105 ++++++------- handlers/thinq/thinq_test.go | 1 + handlers/twiml/twiml_test.go | 42 +++--- handlers/viber/viber_test.go | 30 +++- handlers/vk/vk_test.go | 2 + handlers/wavy/wavy_test.go | 141 ++++++++++++++---- handlers/wechat/wechat_test.go | 30 +++- test/backend.go | 79 +++++----- 28 files changed, 414 insertions(+), 218 deletions(-) diff --git a/handler_test.go b/handler_test.go index 11fa876d2..f58ab6f6a 100644 --- a/handler_test.go +++ b/handler_test.go @@ -103,7 +103,7 @@ func TestHandling(t *testing.T) { assert.Equal(courier.MsgErrored, mb.MsgStatuses()[0].Status()) assert.Equal(1, len(mb.ChannelLogs())) - mb.ClearMsgStatuses() + mb.Reset() // change our channel to our dummy channel msg = test.NewMockMsg(courier.NewMsgID(102), courier.NilMsgUUID, dmChannel, "tel:+250788383383", "test message 2") @@ -117,7 +117,7 @@ func TestHandling(t *testing.T) { assert.Equal(msg.ID(), mb.MsgStatuses()[0].ID()) assert.Equal(courier.MsgSent, mb.MsgStatuses()[0].Status()) - mb.ClearMsgStatuses() + mb.Reset() // send the message again, should be skipped but again marked as wired mb.PushOutgoingMsg(msg) diff --git a/handlers/africastalking/africastalking_test.go b/handlers/africastalking/africastalking_test.go index 4fb75f44e..97559b319 100644 --- a/handlers/africastalking/africastalking_test.go +++ b/handlers/africastalking/africastalking_test.go @@ -90,6 +90,7 @@ var testCases = []ChannelHandleTestCase{ Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Success", ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, }, { Label: "Status Expired", @@ -97,6 +98,7 @@ var testCases = []ChannelHandleTestCase{ Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Expired", ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, }, } diff --git a/handlers/blackmyna/blackmyna_test.go b/handlers/blackmyna/blackmyna_test.go index b1a9ea629..5158246d5 100644 --- a/handlers/blackmyna/blackmyna_test.go +++ b/handlers/blackmyna/blackmyna_test.go @@ -62,6 +62,7 @@ var testCases = []ChannelHandleTestCase{ URL: statusURL + "?id=bmID&status=2", ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, }, } diff --git a/handlers/bongolive/bongolive_test.go b/handlers/bongolive/bongolive_test.go index 215c718af..b08de58e9 100644 --- a/handlers/bongolive/bongolive_test.go +++ b/handlers/bongolive/bongolive_test.go @@ -63,6 +63,7 @@ var testCases = []ChannelHandleTestCase{ Data: "msgtype=5&dlrid=12345&status=1", ExpectedRespStatus: 200, ExpectedRespBody: "", + ExpectedMsgStatus: courier.MsgDelivered, }, { Label: "Invalid Msg Type", diff --git a/handlers/chikka/chikka_test.go b/handlers/chikka/chikka_test.go index 9eeb8cd33..aec9ee56d 100644 --- a/handlers/chikka/chikka_test.go +++ b/handlers/chikka/chikka_test.go @@ -57,6 +57,7 @@ var testCases = []ChannelHandleTestCase{ Data: "message_type=outgoing&message_id=10&status=SENT", ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, }, { Label: "Status Failed Valid", @@ -64,6 +65,7 @@ var testCases = []ChannelHandleTestCase{ Data: "message_type=outgoing&message_id=10&status=FAILED", ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, }, { Label: "Status Invalid", diff --git a/handlers/clickatell/clickatell_test.go b/handlers/clickatell/clickatell_test.go index 20ed559e1..e59870371 100644 --- a/handlers/clickatell/clickatell_test.go +++ b/handlers/clickatell/clickatell_test.go @@ -191,6 +191,7 @@ var testCases = []ChannelHandleTestCase{ Data: `{"messageId": "msg1", "statusCode": 5}`, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, }, { Label: "Valid Delivered status report", @@ -198,6 +199,7 @@ var testCases = []ChannelHandleTestCase{ Data: `{"messageId": "msg1", "statusCode": 4}`, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, }, { Label: "Unexpected status report", diff --git a/handlers/discord/discord_test.go b/handlers/discord/discord_test.go index e95e735e7..1d0d1d464 100644 --- a/handlers/discord/discord_test.go +++ b/handlers/discord/discord_test.go @@ -67,6 +67,7 @@ var testCases = []ChannelHandleTestCase{ Data: `id=12345`, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, }, { Label: "Message Sent Handler Garbage", diff --git a/handlers/dmark/dmark_test.go b/handlers/dmark/dmark_test.go index b3f5246f7..9a45e7980 100644 --- a/handlers/dmark/dmark_test.go +++ b/handlers/dmark/dmark_test.go @@ -61,23 +61,24 @@ var testCases = []ChannelHandleTestCase{ { Label: "Status Invalid", URL: statusURL, - ExpectedRespStatus: 400, Data: "id=12345&status=Borked", + ExpectedRespStatus: 400, ExpectedRespBody: "unknown status", }, { Label: "Status Missing", URL: statusURL, - ExpectedRespStatus: 400, Data: "id=12345", + ExpectedRespStatus: 400, ExpectedRespBody: "field 'status' required", }, { Label: "Status Valid", URL: statusURL, - ExpectedRespStatus: 200, Data: "id=12345&status=1", + ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, }, } diff --git a/handlers/external/external_test.go b/handlers/external/external_test.go index e2972edae..fa2b73e39 100644 --- a/handlers/external/external_test.go +++ b/handlers/external/external_test.go @@ -128,6 +128,7 @@ var handleTestCases = []ChannelHandleTestCase{ URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/failed/?id=12345", ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, }, { Label: "Invalid Status", @@ -139,13 +140,16 @@ var handleTestCases = []ChannelHandleTestCase{ Label: "Sent Valid", URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/sent/?id=12345", ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"S"`}, + ExpectedRespBody: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, + }, { Label: "Delivered Valid", URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered/?id=12345", - ExpectedRespStatus: 200, Data: "nothing", + ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, }, { Label: "Delivered Valid Post", @@ -153,13 +157,16 @@ var handleTestCases = []ChannelHandleTestCase{ Data: "id=12345", ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, }, { Label: "Stopped Event", URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/?from=%2B2349067554729", - ExpectedRespStatus: 200, Data: "nothing", + ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + ExpectedEvent: "stop_contact", + ExpectedURN: "tel:+2349067554729", }, { Label: "Stopped Event Post", @@ -167,6 +174,8 @@ var handleTestCases = []ChannelHandleTestCase{ Data: "from=%2B2349067554729", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + ExpectedEvent: "stop_contact", + ExpectedURN: "tel:+2349067554729", }, { Label: "Stopped Event Invalid URN", diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index 0b5379e51..d1d01cc73 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -547,7 +547,6 @@ var testCases = []ChannelHandleTestCase{ Data: dlr, ExpectedRespStatus: 200, ExpectedRespBody: "Handled", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "mid.1458668856218:ed81099e15d3f4f233", }, @@ -696,6 +695,8 @@ func TestVerify(t *testing.T) { URL: receiveURL, Data: helloMsg, ExpectedRespStatus: 200, + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: "facebook:5678", }, { Label: "Verify No Mode", diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index e64b981a6..8368f9d08 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -181,7 +181,6 @@ var testCasesFBA = []ChannelHandleTestCase{ Data: string(test.ReadFile("./testdata/fba/dlr.json")), ExpectedRespStatus: 200, ExpectedRespBody: "Handled", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "mid.1458668856218:ed81099e15d3f4f233", PrepRequest: addValidSignature, diff --git a/handlers/highconnection/highconnection_test.go b/handlers/highconnection/highconnection_test.go index fb96e5c00..3263443c1 100644 --- a/handlers/highconnection/highconnection_test.go +++ b/handlers/highconnection/highconnection_test.go @@ -72,6 +72,7 @@ var testCases = []ChannelHandleTestCase{ URL: statusURL + "?ret_id=12345&status=6", ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, }, } diff --git a/handlers/infobip/infobip_test.go b/handlers/infobip/infobip_test.go index 309226ca6..f37d9f610 100644 --- a/handlers/infobip/infobip_test.go +++ b/handlers/infobip/infobip_test.go @@ -245,6 +245,7 @@ var testCases = []ChannelHandleTestCase{ Data: validStatusDelivered, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, }, { Label: "Status rejected", @@ -252,6 +253,7 @@ var testCases = []ChannelHandleTestCase{ Data: validStatusRejected, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, }, { Label: "Status undeliverable", @@ -259,19 +261,23 @@ var testCases = []ChannelHandleTestCase{ Data: validStatusUndeliverable, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, }, { Label: "Status pending", URL: statusURL, Data: validStatusPending, ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"S"`}, + ExpectedRespBody: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, + }, { Label: "Status expired", URL: statusURL, Data: validStatusExpired, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, }, { Label: "Status group name unexpected", diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index 79c8ecd79..243032d2c 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -193,13 +193,28 @@ func TestFetchAccessToken(t *testing.T) { fetchTimeout = time.Millisecond RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ - {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted"}, - - {Label: "Verify URL", URL: verifyURL, ExpectedRespStatus: 200, ExpectedRespBody: "SUCCESS", - PrepRequest: addValidSignature}, - - {Label: "Verify URL Invalid signature", URL: verifyURL, ExpectedRespStatus: 400, ExpectedRespBody: "unknown request", - PrepRequest: addInvalidSignature}, + { + Label: "Receive Message", + URL: receiveURL, + Data: validMsg, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Simple Message"), + ExpectedURN: "jiochat:1234", + }, + { + Label: "Verify URL", + URL: verifyURL, + ExpectedRespStatus: 200, + ExpectedRespBody: "SUCCESS", + PrepRequest: addValidSignature, + }, + { + Label: "Verify URL Invalid signature", + URL: verifyURL, + ExpectedRespStatus: 400, + ExpectedRespBody: "unknown request", + PrepRequest: addInvalidSignature}, }) // wait for our fetch to be called diff --git a/handlers/kaleyra/kaleyra_test.go b/handlers/kaleyra/kaleyra_test.go index e34d3f19e..a22f7fa29 100644 --- a/handlers/kaleyra/kaleyra_test.go +++ b/handlers/kaleyra/kaleyra_test.go @@ -91,15 +91,12 @@ var testCases = []ChannelHandleTestCase{ { Label: "Receive Invalid Status", URL: receiveStatusURL + "?id=58f86fab-85c5-4f7c-9b68-9c323248afc4%3A0&status=deleted", - ExpectedExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", - ExpectedMsgStatus: "D", ExpectedRespStatus: 200, ExpectedRespBody: "unknown status", }, { Label: "Receive Blank status", URL: receiveStatusURL, - ExpectedExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", ExpectedRespStatus: 400, ExpectedRespBody: "field 'status' required", }, diff --git a/handlers/kannel/kannel_test.go b/handlers/kannel/kannel_test.go index 674120ffe..2ba76a374 100644 --- a/handlers/kannel/kannel_test.go +++ b/handlers/kannel/kannel_test.go @@ -42,13 +42,13 @@ var handleTestCases = []ChannelHandleTestCase{ {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, {Label: "Status No Params", URL: statusNoParams, ExpectedRespStatus: 400, ExpectedRespBody: "field 'status' required"}, {Label: "Status Invalid Status", URL: statusInvalidStatus, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status '66', must be one of 1,2,4,8,16"}, - {Label: "Status Valid", URL: statusWired, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`}, + {Label: "Status Valid", URL: statusWired, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, ExpectedMsgStatus: courier.MsgSent}, } var ignoreTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Write Status Delivered", URL: statusDelivered, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`}, + {Label: "Write Status Delivered", URL: statusDelivered, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered}, {Label: "Ignore Status Wired", URL: statusWired, ExpectedRespStatus: 200, ExpectedRespBody: `ignoring sent report`}, {Label: "Ignore Status Sent", URL: statusSent, ExpectedRespStatus: 200, ExpectedRespBody: `ignoring sent report`}, } diff --git a/handlers/macrokiosk/macrokiosk_test.go b/handlers/macrokiosk/macrokiosk_test.go index 3d59e3660..92008a231 100644 --- a/handlers/macrokiosk/macrokiosk_test.go +++ b/handlers/macrokiosk/macrokiosk_test.go @@ -45,8 +45,8 @@ var testCases = []ChannelHandleTestCase{ {Label: "Invalid Params", URL: receiveURL, Data: invalidParamsReceive, ExpectedRespStatus: 400, ExpectedRespBody: "missing shortcode, longcode, from or msisdn parameters"}, {Label: "Invalid Address Params", URL: receiveURL, Data: invalidAddress, ExpectedRespStatus: 400, ExpectedRespBody: "invalid to number [1515], expecting [2020]"}, - {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`}, - {Label: "Wired Status", URL: statusURL, Data: processingStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"W"`}, + {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, ExpectedMsgStatus: courier.MsgSent}, + {Label: "Wired Status", URL: statusURL, Data: processingStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"W"`, ExpectedMsgStatus: courier.MsgWired}, {Label: "Unknown Status", URL: statusURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedRespBody: `ignoring unknown status 'UNKNOWN'`}, } diff --git a/handlers/mblox/mblox_test.go b/handlers/mblox/mblox_test.go index 907d41ac8..75a12a9a0 100644 --- a/handlers/mblox/mblox_test.go +++ b/handlers/mblox/mblox_test.go @@ -69,7 +69,7 @@ var testCases = []ChannelHandleTestCase{ {Label: "Receive Missing Params", URL: receiveURL, Data: missingParamsRecieve, ExpectedRespStatus: 400, ExpectedRespBody: "missing one of 'id', 'from', 'to', 'body' or 'received_at' in request body"}, {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, - {Label: "Status Valid", URL: receiveURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`}, + {Label: "Status Valid", URL: receiveURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered}, {Label: "Status Unknown", URL: receiveURL, Data: unknownStatus, ExpectedRespStatus: 400, ExpectedRespBody: `unknown status 'INVALID'`}, {Label: "Status Missing Batch ID", URL: receiveURL, Data: missingBatchID, ExpectedRespStatus: 400, ExpectedRespBody: "missing one of 'batch_id' or 'status' in request body"}, } diff --git a/handlers/nexmo/nexmo_test.go b/handlers/nexmo/nexmo_test.go index 4596699b6..071366d83 100644 --- a/handlers/nexmo/nexmo_test.go +++ b/handlers/nexmo/nexmo_test.go @@ -13,37 +13,93 @@ var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "NX", "2020", "US", nil), } -var ( +const ( statusURL = "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status" receiveURL = "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive" - - receiveValidMessage = "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?to=2020&msisdn=2349067554729&text=Join&messageId=external1" - receiveInvalidURN = "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?to=2020&msisdn=MTN&text=Join&messageId=external1" - receiveValidMessageBody = "to=2020&msisdn=2349067554729&text=Join&messageId=external1" - - statusDelivered = "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=delivered" - statusExpired = "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=expired" - statusFailed = "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=failed" - statusAccepted = "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=accepted" - statusBuffered = "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=buffered" - statusUnexpected = "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=unexpected" ) var testCases = []ChannelHandleTestCase{ - {Label: "Valid Receive", URL: receiveValidMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, - {Label: "Invalid URN", URL: receiveInvalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, - {Label: "Valid Receive Post", URL: receiveURL, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", Data: receiveValidMessageBody, - ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, - {Label: "Receive URL check", URL: receiveURL, ExpectedRespStatus: 200, ExpectedRespBody: "no to parameter, ignored"}, - {Label: "Status URL check", URL: statusURL, ExpectedRespStatus: 200, ExpectedRespBody: "no messageId parameter, ignored"}, - - {Label: "Status delivered", URL: statusDelivered, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "external1"}, - {Label: "Status expired", URL: statusExpired, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, ExpectedExternalID: "external1"}, - {Label: "Status failed", URL: statusFailed, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, ExpectedExternalID: "external1"}, - {Label: "Status accepted", URL: statusAccepted, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, ExpectedExternalID: "external1"}, - {Label: "Status buffered", URL: statusBuffered, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, ExpectedExternalID: "external1"}, - {Label: "Status unexpected", URL: statusUnexpected, ExpectedRespStatus: 200, ExpectedRespBody: "ignoring unknown status report", ExpectedExternalID: "external1"}, + { + Label: "Valid Receive", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?to=2020&msisdn=2349067554729&text=Join&messageId=external1", + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + }, + { + Label: "Invalid URN", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?to=2020&msisdn=MTN&text=Join&messageId=external1", + ExpectedRespStatus: 400, + ExpectedRespBody: "phone number supplied is not a number", + }, + { + Label: "Valid Receive Post", + URL: receiveURL, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + Data: "to=2020&msisdn=2349067554729&text=Join&messageId=external1", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + }, + { + Label: "Receive URL check", + URL: receiveURL, + ExpectedRespStatus: 200, + ExpectedRespBody: "no to parameter, ignored", + }, + { + Label: "Status URL check", + URL: statusURL, + ExpectedRespStatus: 200, + ExpectedRespBody: "no messageId parameter, ignored", + }, + { + Label: "Status delivered", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=delivered", + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, + ExpectedExternalID: "external1", + }, + { + Label: "Status expired", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=expired", + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, + ExpectedExternalID: "external1", + }, + { + Label: "Status failed", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=failed", + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, + ExpectedExternalID: "external1", + }, + { + Label: "Status accepted", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=accepted", + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, + ExpectedExternalID: "external1", + }, + { + Label: "Status buffered", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=buffered", + ExpectedRespStatus: 200, + ExpectedRespBody: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, + ExpectedExternalID: "external1", + }, + { + Label: "Status unexpected", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=unexpected", + ExpectedRespStatus: 200, + ExpectedRespBody: "ignoring unknown status report", + }, } func TestHandler(t *testing.T) { diff --git a/handlers/plivo/plivo_test.go b/handlers/plivo/plivo_test.go index 67e081080..f86a27b69 100644 --- a/handlers/plivo/plivo_test.go +++ b/handlers/plivo/plivo_test.go @@ -35,8 +35,8 @@ var testCases = []ChannelHandleTestCase{ {Label: "Invalid Address Params", URL: receiveURL, Data: invalidAddress, ExpectedRespStatus: 400, ExpectedRespBody: "invalid to number [1515], expecting [2020]"}, {Label: "Missing Params", URL: receiveURL, Data: missingParams, ExpectedRespStatus: 400, ExpectedRespBody: "Field validation for 'To' failed"}, - {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`}, - {Label: "Sent Status", URL: statusURL, Data: validSentStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`}, + {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered}, + {Label: "Sent Status", URL: statusURL, Data: validSentStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, ExpectedMsgStatus: courier.MsgSent}, {Label: "Invalid Status Address", URL: statusURL, Data: invalidStatusAddress, ExpectedRespStatus: 400, ExpectedRespBody: "invalid to number [1515], expecting [2020]"}, {Label: "Unkown Status", URL: statusURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedRespBody: `ignoring unknown status 'UNKNOWN'`}, } diff --git a/handlers/test.go b/handlers/test.go index d5f9c9d70..4d647a60f 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -301,8 +301,8 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour } if tc.ExpectedStopEvent { - evt, err := mb.GetLastChannelEvent() - require.NoError(err) + evt := mb.LastWrittenChannelEvent() + require.NotNil(evt) require.Equal(courier.StopContact, evt.EventType()) } @@ -350,75 +350,64 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri testHandlerRequest(t, s, tc.URL, tc.Headers, tc.Data, tc.MultipartForm, tc.ExpectedRespStatus, &tc.ExpectedRespBody, tc.PrepRequest) - // pop our message off and test against it + msg := mb.LastWrittenMsg() + status := mb.LastWrittenMsgStatus() + event := mb.LastWrittenChannelEvent() contactName := mb.GetLastContactName() - msg, _ := mb.GetLastQueueMsg() - event, _ := mb.GetLastChannelEvent() - status, _ := mb.GetLastMsgStatus() - if tc.ExpectedRespStatus == 200 { - if tc.ExpectedContactName != nil { - require.Equal(*tc.ExpectedContactName, contactName) - } + if tc.ExpectedMsgText != nil || tc.ExpectedAttachments != nil { + require.NotNil(msg, "expected a msg to be written") + if tc.ExpectedMsgText != nil { - require.NotNil(msg) - require.Equal(mb.LenQueuedMsgs(), 1) - require.Equal(*tc.ExpectedMsgText, msg.Text()) - } - if tc.ExpectedEvent != "" { - assert.Equal(t, tc.ExpectedEvent, event.EventType()) - } - if tc.ExpectedEventExtra != nil { - require.Equal(tc.ExpectedEventExtra, event.Extra()) + assert.Equal(t, mb.LenQueuedMsgs(), 1) + assert.Equal(t, *tc.ExpectedMsgText, msg.Text()) } - if tc.ExpectedURN != "" { - if msg != nil { - assert.Equal(t, tc.ExpectedURN, msg.URN()) - } else if event != nil { - assert.Equal(t, tc.ExpectedURN, event.URN()) - } else { - assert.Equal(t, tc.ExpectedURN, "") - } + if len(tc.ExpectedAttachments) > 0 { + assert.Equal(t, tc.ExpectedAttachments, msg.Attachments()) } - if tc.ExpectedURNAuth != "" { - if msg != nil { - assert.Equal(t, tc.ExpectedURNAuth, msg.URNAuth()) - } else { - assert.Equal(t, tc.ExpectedURNAuth, "") - } + if !tc.ExpectedDate.IsZero() { + assert.Equal(t, tc.ExpectedDate.Local(), msg.ReceivedOn().Local()) } if tc.ExpectedExternalID != "" { - if msg != nil { - assert.Equal(t, tc.ExpectedExternalID, msg.ExternalID()) - } else if status != nil { - assert.Equal(t, tc.ExpectedExternalID, status.ExternalID()) - } else { - assert.Equal(t, tc.ExpectedExternalID, "") - } + assert.Equal(t, tc.ExpectedExternalID, msg.ExternalID()) } - if tc.ExpectedMsgStatus != "" { - require.NotNil(status) - require.Equal(tc.ExpectedMsgStatus, status.Status()) + assert.Equal(t, tc.ExpectedURN, msg.URN()) + assert.Equal(t, tc.ExpectedURNAuth, msg.URNAuth()) + } else { + assert.Nil(t, msg, "unexpected msg written") + } + + if tc.ExpectedMsgStatus != "" { + require.NotNil(status, "expected a msg status to be written") + + assert.Equal(t, tc.ExpectedMsgStatus, status.Status()) + + if tc.ExpectedExternalID != "" { + assert.Equal(t, tc.ExpectedExternalID, status.ExternalID()) } if tc.ExpectedMsgID != 0 { - if status != nil { - require.Equal(tc.ExpectedMsgID, int64(status.ID())) - } else { - require.Equal(tc.ExpectedMsgID, -1) - } - } - if len(tc.ExpectedAttachments) > 0 { - require.Equal(tc.ExpectedAttachments, msg.Attachments()) + assert.Equal(t, tc.ExpectedMsgID, int64(status.ID())) } + } else { + assert.Nil(t, status, "unexpected msg status written") + } + + if tc.ExpectedEvent != "" { + require.NotNil(event, "expected a channel event to be written") + + assert.Equal(t, tc.ExpectedEvent, event.EventType()) + assert.Equal(t, tc.ExpectedEventExtra, event.Extra()) + assert.Equal(t, tc.ExpectedURN, event.URN()) + if !tc.ExpectedDate.IsZero() { - if msg != nil { - require.Equal((tc.ExpectedDate).Local(), (*msg.ReceivedOn()).Local()) - } else if event != nil { - require.Equal(tc.ExpectedDate, event.OccurredOn()) - } else { - require.Equal(tc.ExpectedDate, nil) - } + assert.Equal(t, tc.ExpectedDate, event.OccurredOn()) } + } else { + assert.Nil(t, event, "unexpected channel event written") + } + + if tc.ExpectedContactName != nil { + require.Equal(*tc.ExpectedContactName, contactName) } // if we're expecting a message, status or event, check we have a log for it diff --git a/handlers/thinq/thinq_test.go b/handlers/thinq/thinq_test.go index ea15b73dc..4597abfb3 100644 --- a/handlers/thinq/thinq_test.go +++ b/handlers/thinq/thinq_test.go @@ -65,6 +65,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedRespStatus: 200, ExpectedExternalID: "1234", ExpectedRespBody: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, }, { Label: "Status Invalid", diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index dee7bdd91..2572da19c 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -96,19 +96,19 @@ var testCases = []ChannelHandleTestCase{ {Label: "Receive Base64", URL: receiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status Stop contact", URL: statusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, + {Label: "Status Stop contact", URL: statusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", PrepRequest: addValidSignature}, {Label: "Status No Params", URL: statusURL, Data: " ", ExpectedRespStatus: 200, ExpectedRespBody: "no msg status, ignoring", PrepRequest: addValidSignature}, {Label: "Status Invalid Status", URL: statusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: statusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status Valid", URL: statusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status Read", URL: statusURL, Data: statusRead, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status Read", URL: statusURL, Data: statusRead, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status ID Valid", URL: statusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgID: 12345, + {Label: "Status ID Valid", URL: statusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: statusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status ID Invalid", URL: statusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } @@ -133,19 +133,19 @@ var tmsTestCases = []ChannelHandleTestCase{ {Label: "Receive Base64", URL: tmsReceiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status Stop contact", URL: tmsStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, + {Label: "Status Stop contact", URL: tmsStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", PrepRequest: addValidSignature}, - {Label: "Status TMS extra", URL: tmsStatusURL, Data: tmsStatusExtra, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, + {Label: "Status TMS extra", URL: tmsStatusURL, Data: tmsStatusExtra, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, ExpectedMsgStatus: courier.MsgSent, ExpectedExternalID: "SM0b6e2697aae04182a9f5b5c7a8994c7f", PrepRequest: addValidSignature}, {Label: "Status No Params", URL: tmsStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedRespBody: "no msg status, ignoring", PrepRequest: addValidSignature}, {Label: "Status Invalid Status", URL: tmsStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: tmsStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status Valid", URL: tmsStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status ID Valid", URL: tmsStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgID: 12345, + {Label: "Status ID Valid", URL: tmsStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: tmsStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status ID Invalid", URL: tmsStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } @@ -172,17 +172,17 @@ var twTestCases = []ChannelHandleTestCase{ {Label: "Receive Base64", URL: twReceiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status Stop contact", URL: twStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, + {Label: "Status Stop contact", URL: twStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", PrepRequest: addValidSignature}, {Label: "Status No Params", URL: twStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedRespBody: "no msg status, ignoring", PrepRequest: addValidSignature}, {Label: "Status Invalid Status", URL: twStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: twStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status Valid", URL: twStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status ID Valid", URL: twStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgID: 12345, + {Label: "Status ID Valid", URL: twStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: twStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status ID Invalid", URL: twStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } @@ -196,13 +196,13 @@ var swTestCases = []ChannelHandleTestCase{ ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}}, {Label: "Receive Base64", URL: swReceiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedRespBody: "", ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, - {Label: "Status Stop contact", URL: swStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, + {Label: "Status Stop contact", URL: swStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", PrepRequest: addValidSignature}, {Label: "Status No Params", URL: swStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedRespBody: "no msg status, ignoring"}, {Label: "Status Invalid Status", URL: swStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status 'huh'"}, - {Label: "Status Valid", URL: swStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, - {Label: "Status ID Valid", URL: swStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgID: 12345}, - {Label: "Status ID Invalid", URL: swStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, + {Label: "Status Valid", URL: swStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, + {Label: "Status ID Valid", URL: swStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedMsgID: 12345}, + {Label: "Status ID Invalid", URL: swStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, } var waTestCases = []ChannelHandleTestCase{ @@ -225,11 +225,11 @@ var twaTestCases = []ChannelHandleTestCase{ PrepRequest: addValidSignature}, {Label: "Status Invalid Status", URL: twaStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: twaStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status Valid", URL: twaStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status ID Valid", URL: twaStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgID: 12345, + {Label: "Status ID Valid", URL: twaStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: twaStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status ID Invalid", URL: twaStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index fb41698d1..8e371e5e0 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -493,11 +493,11 @@ var testCases = []ChannelHandleTestCase{ {Label: "Receive invalid Message Type", URL: receiveURL, Data: receiveInvalidMessageType, ExpectedRespStatus: 400, ExpectedRespBody: "unknown message type", PrepRequest: addValidSignature}, {Label: "Webhook validation", URL: receiveURL, Data: webhookCheck, ExpectedRespStatus: 200, ExpectedRespBody: "webhook valid", PrepRequest: addValidSignature}, - {Label: "Failed Status Report", URL: receiveURL, Data: failedStatusReport, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, PrepRequest: addValidSignature}, + {Label: "Failed Status Report", URL: receiveURL, Data: failedStatusReport, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, PrepRequest: addValidSignature}, {Label: "Delivered Status Report", URL: receiveURL, Data: deliveredStatusReport, ExpectedRespStatus: 200, ExpectedRespBody: `Ignored`, PrepRequest: addValidSignature}, - {Label: "Subcribe", URL: receiveURL, Data: validSubscribed, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", PrepRequest: addValidSignature}, + {Label: "Subcribe", URL: receiveURL, Data: validSubscribed, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedEvent: "new_conversation", ExpectedURN: "viber:01234567890A=", PrepRequest: addValidSignature}, {Label: "Subcribe Invalid URN", URL: receiveURL, Data: invalidURNSubscribed, ExpectedRespStatus: 400, ExpectedRespBody: "invalid viber id", PrepRequest: addValidSignature}, - {Label: "Unsubcribe", URL: receiveURL, Data: validUnsubscribed, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedEvent: courier.StopContact, PrepRequest: addValidSignature}, + {Label: "Unsubcribe", URL: receiveURL, Data: validUnsubscribed, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedEvent: courier.StopContact, ExpectedURN: "viber:01234567890A=", PrepRequest: addValidSignature}, {Label: "Unsubcribe Invalid URN", URL: receiveURL, Data: invalidURNUnsubscribed, ExpectedRespStatus: 400, ExpectedRespBody: "invalid viber id", PrepRequest: addValidSignature}, {Label: "Conversation Started", URL: receiveURL, Data: validConversationStarted, ExpectedRespStatus: 200, ExpectedRespBody: "ignored conversation start", PrepRequest: addValidSignature}, {Label: "Unexpected event", URL: receiveURL, Data: unexpectedEvent, ExpectedRespStatus: 400, @@ -522,10 +522,26 @@ var testCases = []ChannelHandleTestCase{ } var testWelcomeMessageCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("incoming msg"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", - PrepRequest: addValidSignature}, - {Label: "Conversation Started", URL: receiveURL, Data: validConversationStarted, ExpectedRespStatus: 200, ExpectedRespBody: `{"auth_token":"Token","text":"Welcome to VP, Please subscribe here for more.","type":"text","tracking_data":"0"}`, PrepRequest: addValidSignature}, + { + Label: "Receive Valid", + URL: receiveURL, + Data: validMsg, + ExpectedRespStatus: 200, + ExpectedRespBody: "Accepted", + ExpectedMsgText: Sp("incoming msg"), + ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + ExpectedExternalID: "4987381189870374000", + PrepRequest: addValidSignature}, + { + Label: "Conversation Started", + URL: receiveURL, + Data: validConversationStarted, + ExpectedRespStatus: 200, + ExpectedRespBody: `{"auth_token":"Token","text":"Welcome to VP, Please subscribe here for more.","type":"text","tracking_data":"0"}`, + ExpectedEvent: "welcome_message", + ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + PrepRequest: addValidSignature, + }, } func addValidSignature(r *http.Request) { diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index bc1c239c1..a0759cac6 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -236,6 +236,7 @@ var testCases = []ChannelHandleTestCase{ Data: msgHelloWorld, ExpectedRespStatus: 200, ExpectedRespBody: "ok", + ExpectedMsgText: Sp("Hello World"), ExpectedURN: "vk:123456", ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), @@ -311,6 +312,7 @@ var testCases = []ChannelHandleTestCase{ Data: msgKeyboard, ExpectedRespStatus: 200, ExpectedRespBody: "ok", + ExpectedMsgText: Sp("Yes"), ExpectedURN: "vk:123456", ExpectedExternalID: "1", ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), diff --git a/handlers/wavy/wavy_test.go b/handlers/wavy/wavy_test.go index a91c5f577..dc7d2734e 100644 --- a/handlers/wavy/wavy_test.go +++ b/handlers/wavy/wavy_test.go @@ -38,10 +38,6 @@ var ( } }` - missingRequiredKeys = `{}` - - notJSON = `blargh` - validSentStatus = `{ "id": "58b36497-fb0f-474c-9c35-20b184ac4227", "correlationId": "12345", @@ -79,20 +75,89 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", - ExpectedMsgText: Sp("Eu quero pizza"), ExpectedURN: "tel:+5516981562820", ExpectedExternalID: "external_id", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC)}, - {Label: "Invalid JSON receive", URL: receiveURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, - {Label: "Missing Keys receive", URL: receiveURL, Data: missingRequiredKeys, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'ID' failed on the 'required'"}, - - {Label: "Sent Status Valid", URL: sentStatusURL, Data: validSentStatus, ExpectedRespStatus: 200, ExpectedRespBody: "Status Update Accepted", ExpectedMsgStatus: courier.MsgSent}, - {Label: "Unknown Sent Status Valid", URL: sentStatusURL, Data: unknownSentStatus, ExpectedRespStatus: 400, ExpectedRespBody: "unknown sent status code", ExpectedMsgStatus: courier.MsgWired}, - {Label: "Invalid JSON sent Status", URL: sentStatusURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, - {Label: "Missing Keys sent Status", URL: sentStatusURL, Data: missingRequiredKeys, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'CollerationID' failed on the 'required'"}, - - {Label: "Delivered Status Valid", URL: deliveredStatusURL, Data: validDeliveredStatus, ExpectedRespStatus: 200, ExpectedRespBody: "Status Update Accepted", ExpectedMsgStatus: courier.MsgDelivered}, - {Label: "Unknown Delivered Status Valid", URL: deliveredStatusURL, Data: unknownDeliveredStatus, ExpectedRespStatus: 400, ExpectedRespBody: "unknown delivered status code", ExpectedMsgStatus: courier.MsgSent}, - {Label: "Invalid JSON delivered Statu", URL: deliveredStatusURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, - {Label: "Missing Keys sent Status", URL: deliveredStatusURL, Data: missingRequiredKeys, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'CollerationID' failed on the 'required'"}, + { + Label: "Receive Message", + URL: receiveURL, + Data: validReceive, + ExpectedRespStatus: 200, + ExpectedRespBody: "Message Accepted", + ExpectedMsgText: Sp("Eu quero pizza"), + ExpectedURN: "tel:+5516981562820", + ExpectedExternalID: "external_id", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + }, + { + Label: "Invalid JSON receive", + URL: receiveURL, + Data: `blargh`, + ExpectedRespStatus: 400, + ExpectedRespBody: "unable to parse request JSON", + }, + { + Label: "Missing Keys receive", + URL: receiveURL, + Data: `{}`, + ExpectedRespStatus: 400, + ExpectedRespBody: "validation for 'ID' failed on the 'required'", + }, + { + Label: "Sent Status Valid", + URL: sentStatusURL, + Data: validSentStatus, + ExpectedRespStatus: 200, + ExpectedRespBody: "Status Update Accepted", + ExpectedMsgStatus: courier.MsgSent, + }, + { + Label: "Unknown Sent Status Valid", + URL: sentStatusURL, + Data: unknownSentStatus, + ExpectedRespStatus: 400, + ExpectedRespBody: "unknown sent status code", + }, + { + Label: "Invalid JSON sent Status", + URL: sentStatusURL, + Data: `blargh`, + ExpectedRespStatus: 400, + ExpectedRespBody: "unable to parse request JSON", + }, + { + Label: "Missing Keys sent Status", + URL: sentStatusURL, + Data: `{}`, + ExpectedRespStatus: 400, + ExpectedRespBody: "validation for 'CollerationID' failed on the 'required'", + }, + { + Label: "Delivered Status Valid", + URL: deliveredStatusURL, + Data: validDeliveredStatus, + ExpectedRespStatus: 200, + ExpectedRespBody: "Status Update Accepted", + ExpectedMsgStatus: courier.MsgDelivered, + }, + { + Label: "Unknown Delivered Status Valid", + URL: deliveredStatusURL, + Data: unknownDeliveredStatus, + ExpectedRespStatus: 400, + ExpectedRespBody: "unknown delivered status code", + }, + { + Label: "Invalid JSON delivered Statu", + URL: deliveredStatusURL, + Data: `blargh`, + ExpectedRespStatus: 400, + ExpectedRespBody: "unable to parse request JSON", + }, + { + Label: "Missing Keys sent Status", + URL: deliveredStatusURL, + Data: `{}`, + ExpectedRespStatus: 400, + ExpectedRespBody: "validation for 'CollerationID' failed on the 'required'", + }, } func TestHandler(t *testing.T) { @@ -108,25 +173,37 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message ☺", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedMsgStatus: "W", - ExpectedExternalID: "external1", + { + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MockResponseBody: `{"id": "external1"}`, MockResponseStatus: 200, ExpectedHeaders: map[string]string{"username": "user1", "authenticationtoken": "token", "Accept": "application/json", "Content-Type": "application/json"}, ExpectedRequestBody: `{"destination":"250788383383","messageText":"Simple Message ☺\nhttps://foo.bar/image.jpg"}`, - SendPrep: setSendURL}, - {Label: "Error status 403", - MsgText: "Error Response", MsgURN: "tel:+250788383383", + ExpectedMsgStatus: "W", + ExpectedExternalID: "external1", + SendPrep: setSendURL, + }, + { + Label: "Error status 403", + MsgText: "Error Response", + MsgURN: "tel:+250788383383", + MockResponseStatus: 403, ExpectedMsgStatus: "E", - ExpectedRequestBody: `{"destination":"250788383383","messageText":"Error Response"}`, MockResponseStatus: 403, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", - ExpectedMsgStatus: "E", - MockResponseBody: `Bad Gateway`, MockResponseStatus: 501, - SendPrep: setSendURL}, + ExpectedRequestBody: `{"destination":"250788383383","messageText":"Error Response"}`, + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `Bad Gateway`, + MockResponseStatus: 501, + ExpectedMsgStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index 716157777..55affcb3a 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -188,13 +188,29 @@ func TestFetchAccessToken(t *testing.T) { fetchTimeout = time.Millisecond RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ - {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedRespBody: ""}, - - {Label: "Verify URL", URL: receiveURL, ExpectedRespStatus: 200, ExpectedRespBody: "SUCCESS", - PrepRequest: addValidSignature}, - - {Label: "Verify URL Invalid signature", URL: receiveURL, ExpectedRespStatus: 400, ExpectedRespBody: "unknown request", - PrepRequest: addInvalidSignature}, + { + Label: "Receive Message", + URL: receiveURL, + Data: validMsg, + ExpectedRespStatus: 200, + ExpectedRespBody: "", + ExpectedMsgText: Sp("Simple Message"), + ExpectedURN: "wechat:1234", + }, + { + Label: "Verify URL", + URL: receiveURL, + ExpectedRespStatus: 200, + ExpectedRespBody: "SUCCESS", + PrepRequest: addValidSignature, + }, + { + Label: "Verify URL Invalid signature", + URL: receiveURL, + ExpectedRespStatus: 400, + ExpectedRespBody: "unknown request", + PrepRequest: addInvalidSignature, + }, }) // wait for our fetch to be called diff --git a/test/backend.go b/test/backend.go index c3a1d3e6f..f3246206e 100644 --- a/test/backend.go +++ b/test/backend.go @@ -6,12 +6,11 @@ import ( "sync" "time" + "github.com/gomodule/redigo/redis" + _ "github.com/lib/pq" "github.com/nyaruka/courier" "github.com/nyaruka/gocommon/urns" "github.com/nyaruka/gocommon/uuids" - - "github.com/gomodule/redigo/redis" - _ "github.com/lib/pq" // postgres driver "github.com/pkg/errors" ) @@ -29,14 +28,14 @@ type MockBackend struct { mutex sync.RWMutex redisPool *redis.Pool - lastMsgID courier.MsgID - queueMsgs []courier.Msg - outgoingMsgs []courier.Msg - msgStatuses []courier.MsgStatus - channelEvents []courier.ChannelEvent - channelLogs []*courier.ChannelLog + writtenMsgs []courier.Msg + writtenMsgStatuses []courier.MsgStatus + writtenChannelEvents []courier.ChannelEvent + writtenChannelLogs []*courier.ChannelLog + poppedOutgoingMsgs []courier.Msg + lastMsgID courier.MsgID lastContactName string sentMsgs map[courier.MsgID]bool seenExternalIDs []string @@ -76,32 +75,31 @@ func NewMockBackend() *MockBackend { } } -func (mb *MockBackend) ChannelLogs() []*courier.ChannelLog { return mb.channelLogs } -func (mb *MockBackend) MsgStatuses() []courier.MsgStatus { return mb.msgStatuses } -func (mb *MockBackend) ClearMsgStatuses() { mb.msgStatuses = nil } +func (mb *MockBackend) ChannelLogs() []*courier.ChannelLog { return mb.writtenChannelLogs } +func (mb *MockBackend) MsgStatuses() []courier.MsgStatus { return mb.writtenMsgStatuses } -// GetLastQueueMsg returns the last message queued to the server -func (mb *MockBackend) GetLastQueueMsg() (courier.Msg, error) { - if len(mb.queueMsgs) == 0 { - return nil, courier.ErrMsgNotFound +// LastWrittenMsg returns the last message queued to the server +func (mb *MockBackend) LastWrittenMsg() courier.Msg { + if len(mb.writtenMsgs) == 0 { + return nil } - return mb.queueMsgs[len(mb.queueMsgs)-1], nil + return mb.writtenMsgs[len(mb.writtenMsgs)-1] } -// GetLastChannelEvent returns the last event written to the server -func (mb *MockBackend) GetLastChannelEvent() (courier.ChannelEvent, error) { - if len(mb.channelEvents) == 0 { - return nil, errors.New("no channel events") +// LastWrittenChannelEvent returns the last event written to the server +func (mb *MockBackend) LastWrittenChannelEvent() courier.ChannelEvent { + if len(mb.writtenChannelEvents) == 0 { + return nil } - return mb.channelEvents[len(mb.channelEvents)-1], nil + return mb.writtenChannelEvents[len(mb.writtenChannelEvents)-1] } -// GetLastMsgStatus returns the last status written to the server -func (mb *MockBackend) GetLastMsgStatus() (courier.MsgStatus, error) { - if len(mb.msgStatuses) == 0 { - return nil, errors.New("no msg statuses") +// LastWrittenMsgStatus returns the last status written to the server +func (mb *MockBackend) LastWrittenMsgStatus() courier.MsgStatus { + if len(mb.writtenMsgStatuses) == 0 { + return nil } - return mb.msgStatuses[len(mb.msgStatuses)-1], nil + return mb.writtenMsgStatuses[len(mb.writtenMsgStatuses)-1] } // GetLastContactName returns the contact name set on the last msg or channel event written @@ -134,7 +132,7 @@ func (mb *MockBackend) PushOutgoingMsg(msg courier.Msg) { mb.mutex.Lock() defer mb.mutex.Unlock() - mb.outgoingMsgs = append(mb.outgoingMsgs, msg) + mb.poppedOutgoingMsgs = append(mb.poppedOutgoingMsgs, msg) } // PopNextOutgoingMsg returns the next message that should be sent, or nil if there are none to send @@ -142,9 +140,9 @@ func (mb *MockBackend) PopNextOutgoingMsg(ctx context.Context) (courier.Msg, err mb.mutex.Lock() defer mb.mutex.Unlock() - if len(mb.outgoingMsgs) > 0 { - msg, rest := mb.outgoingMsgs[0], mb.outgoingMsgs[1:] - mb.outgoingMsgs = rest + if len(mb.poppedOutgoingMsgs) > 0 { + msg, rest := mb.poppedOutgoingMsgs[0], mb.poppedOutgoingMsgs[1:] + mb.poppedOutgoingMsgs = rest return msg, nil } @@ -180,7 +178,7 @@ func (mb *MockBackend) WriteChannelLog(ctx context.Context, clog *courier.Channe mb.mutex.Lock() defer mb.mutex.Unlock() - mb.channelLogs = append(mb.channelLogs, clog) + mb.writtenChannelLogs = append(mb.writtenChannelLogs, clog) return nil } @@ -205,7 +203,7 @@ func (mb *MockBackend) WriteMsg(ctx context.Context, m courier.Msg, clog *courie return errors.New("unable to queue message") } - mb.queueMsgs = append(mb.queueMsgs, m) + mb.writtenMsgs = append(mb.writtenMsgs, m) mb.lastContactName = m.(*mockMsg).contactName return nil } @@ -235,7 +233,7 @@ func (mb *MockBackend) WriteMsgStatus(ctx context.Context, status courier.MsgSta mb.mutex.Lock() defer mb.mutex.Unlock() - mb.msgStatuses = append(mb.msgStatuses, status) + mb.writtenMsgStatuses = append(mb.writtenMsgStatuses, status) return nil } @@ -253,7 +251,7 @@ func (mb *MockBackend) WriteChannelEvent(ctx context.Context, event courier.Chan mb.mutex.Lock() defer mb.mutex.Unlock() - mb.channelEvents = append(mb.channelEvents, event) + mb.writtenChannelEvents = append(mb.writtenChannelEvents, event) mb.lastContactName = event.(*mockChannelEvent).contactName return nil } @@ -295,7 +293,7 @@ func (mb *MockBackend) AddURNtoContact(context context.Context, channel courier. // RemoveURNFromcontact removes a URN from the passed in contact func (mb *MockBackend) RemoveURNfromContact(context context.Context, channel courier.Channel, contact courier.Contact, urn urns.URN) (urns.URN, error) { - contact, found := mb.contacts[urn] + _, found := mb.contacts[urn] if found { delete(mb.contacts, urn) } @@ -326,14 +324,17 @@ func (mb *MockBackend) Cleanup() error { return nil } // Reset clears our queued messages, seen external IDs, and channel logs func (mb *MockBackend) Reset() { mb.lastMsgID = courier.NilMsgID - mb.queueMsgs = nil mb.seenExternalIDs = nil - mb.channelLogs = nil + + mb.writtenMsgs = nil + mb.writtenMsgStatuses = nil + mb.writtenChannelEvents = nil + mb.writtenChannelLogs = nil } // LenQueuedMsgs Get the length of queued msgs func (mb *MockBackend) LenQueuedMsgs() int { - return len(mb.queueMsgs) + return len(mb.writtenMsgs) } // CheckExternalIDSeen checks if external ID has been seen in a period From ebf8f9d3f97205860d27753e935eb3770b5aeb70 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 7 Sep 2022 17:25:17 -0500 Subject: [PATCH 144/294] Rename some mock backend methods for clarity --- handler_test.go | 20 ++++++++++---------- handlers/test.go | 34 ++++++++++++++++----------------- test/backend.go | 49 +++++++++++------------------------------------- 3 files changed, 38 insertions(+), 65 deletions(-) diff --git a/handler_test.go b/handler_test.go index f58ab6f6a..1161ae472 100644 --- a/handler_test.go +++ b/handler_test.go @@ -98,10 +98,10 @@ func TestHandling(t *testing.T) { time.Sleep(time.Second) // message should have errored because we don't have a registered handler - assert.Equal(1, len(mb.MsgStatuses())) - assert.Equal(msg.ID(), mb.MsgStatuses()[0].ID()) - assert.Equal(courier.MsgErrored, mb.MsgStatuses()[0].Status()) - assert.Equal(1, len(mb.ChannelLogs())) + assert.Equal(1, len(mb.WrittenMsgStatuses())) + assert.Equal(msg.ID(), mb.WrittenMsgStatuses()[0].ID()) + assert.Equal(courier.MsgErrored, mb.WrittenMsgStatuses()[0].Status()) + assert.Equal(1, len(mb.WrittenChannelLogs())) mb.Reset() @@ -113,9 +113,9 @@ func TestHandling(t *testing.T) { time.Sleep(time.Second) // message should be marked as wired - assert.Equal(1, len(mb.MsgStatuses())) - assert.Equal(msg.ID(), mb.MsgStatuses()[0].ID()) - assert.Equal(courier.MsgSent, mb.MsgStatuses()[0].Status()) + assert.Equal(1, len(mb.WrittenMsgStatuses())) + assert.Equal(msg.ID(), mb.WrittenMsgStatuses()[0].ID()) + assert.Equal(courier.MsgSent, mb.WrittenMsgStatuses()[0].Status()) mb.Reset() @@ -124,9 +124,9 @@ func TestHandling(t *testing.T) { time.Sleep(time.Second) // message should be marked as wired - assert.Equal(1, len(mb.MsgStatuses())) - assert.Equal(msg.ID(), mb.MsgStatuses()[0].ID()) - assert.Equal(courier.MsgWired, mb.MsgStatuses()[0].Status()) + assert.Equal(1, len(mb.WrittenMsgStatuses())) + assert.Equal(msg.ID(), mb.WrittenMsgStatuses()[0].ID()) + assert.Equal(courier.MsgWired, mb.WrittenMsgStatuses()[0].Status()) // try to receive a message instead resp, err := http.Get("http://localhost:8080/c/dm/e4bb1578-29da-4fa5-a214-9da19dd24230/receive") diff --git a/handlers/test.go b/handlers/test.go index 4d647a60f..f95502586 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -194,6 +194,8 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour for _, tc := range testCases { mockRRCount := 0 + mb.Reset() + t.Run(tc.Label, func(t *testing.T) { require := require.New(t) @@ -301,9 +303,9 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour } if tc.ExpectedStopEvent { - evt := mb.LastWrittenChannelEvent() - require.NotNil(evt) - require.Equal(courier.StopContact, evt.EventType()) + require.Len(mb.WrittenChannelEvents(), 1) + event := mb.WrittenChannelEvents()[0] + require.Equal(courier.StopContact, event.EventType()) } if tc.ExpectedContactURNs != nil { @@ -350,16 +352,11 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri testHandlerRequest(t, s, tc.URL, tc.Headers, tc.Data, tc.MultipartForm, tc.ExpectedRespStatus, &tc.ExpectedRespBody, tc.PrepRequest) - msg := mb.LastWrittenMsg() - status := mb.LastWrittenMsgStatus() - event := mb.LastWrittenChannelEvent() - contactName := mb.GetLastContactName() - if tc.ExpectedMsgText != nil || tc.ExpectedAttachments != nil { - require.NotNil(msg, "expected a msg to be written") + require.Len(mb.WrittenMsgs(), 1, "expected a msg to be written") + msg := mb.WrittenMsgs()[0] if tc.ExpectedMsgText != nil { - assert.Equal(t, mb.LenQueuedMsgs(), 1) assert.Equal(t, *tc.ExpectedMsgText, msg.Text()) } if len(tc.ExpectedAttachments) > 0 { @@ -374,11 +371,13 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri assert.Equal(t, tc.ExpectedURN, msg.URN()) assert.Equal(t, tc.ExpectedURNAuth, msg.URNAuth()) } else { - assert.Nil(t, msg, "unexpected msg written") + assert.Empty(t, mb.WrittenMsgs(), "unexpected msg written") } if tc.ExpectedMsgStatus != "" { - require.NotNil(status, "expected a msg status to be written") + // TODO fix duplicate statuses + require.Greater(len(mb.WrittenMsgStatuses()), 0, "expected a msg status to be written") + status := mb.WrittenMsgStatuses()[len(mb.WrittenMsgStatuses())-1] assert.Equal(t, tc.ExpectedMsgStatus, status.Status()) @@ -389,11 +388,12 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri assert.Equal(t, tc.ExpectedMsgID, int64(status.ID())) } } else { - assert.Nil(t, status, "unexpected msg status written") + assert.Empty(t, mb.WrittenMsgStatuses(), "unexpected msg status written") } if tc.ExpectedEvent != "" { - require.NotNil(event, "expected a channel event to be written") + require.Len(mb.WrittenChannelEvents(), 1, "expected a channel event to be written") + event := mb.WrittenChannelEvents()[0] assert.Equal(t, tc.ExpectedEvent, event.EventType()) assert.Equal(t, tc.ExpectedEventExtra, event.Extra()) @@ -403,16 +403,16 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri assert.Equal(t, tc.ExpectedDate, event.OccurredOn()) } } else { - assert.Nil(t, event, "unexpected channel event written") + assert.Empty(t, mb.WrittenChannelEvents(), "unexpected channel event written") } if tc.ExpectedContactName != nil { - require.Equal(*tc.ExpectedContactName, contactName) + require.Equal(*tc.ExpectedContactName, mb.LastContactName()) } // if we're expecting a message, status or event, check we have a log for it if tc.ExpectedMsgText != nil || tc.ExpectedMsgStatus != "" || tc.ExpectedEvent != "" { - assert.Greater(t, len(mb.ChannelLogs()), 0, "expected at least one channel log") + assert.Greater(t, len(mb.WrittenChannelLogs()), 0, "expected at least one channel log") } }) } diff --git a/test/backend.go b/test/backend.go index f3246206e..0dd540551 100644 --- a/test/backend.go +++ b/test/backend.go @@ -23,6 +23,7 @@ type MockBackend struct { channels map[courier.ChannelUUID]courier.Channel channelsByAddress map[courier.ChannelAddress]courier.Channel contacts map[urns.URN]courier.Contact + outgoingMsgs []courier.Msg media map[string]courier.Media // url -> Media errorOnQueue bool @@ -33,7 +34,6 @@ type MockBackend struct { writtenMsgStatuses []courier.MsgStatus writtenChannelEvents []courier.ChannelEvent writtenChannelLogs []*courier.ChannelLog - poppedOutgoingMsgs []courier.Msg lastMsgID courier.MsgID lastContactName string @@ -75,35 +75,13 @@ func NewMockBackend() *MockBackend { } } -func (mb *MockBackend) ChannelLogs() []*courier.ChannelLog { return mb.writtenChannelLogs } -func (mb *MockBackend) MsgStatuses() []courier.MsgStatus { return mb.writtenMsgStatuses } +func (mb *MockBackend) WrittenMsgs() []courier.Msg { return mb.writtenMsgs } +func (mb *MockBackend) WrittenMsgStatuses() []courier.MsgStatus { return mb.writtenMsgStatuses } +func (mb *MockBackend) WrittenChannelEvents() []courier.ChannelEvent { return mb.writtenChannelEvents } +func (mb *MockBackend) WrittenChannelLogs() []*courier.ChannelLog { return mb.writtenChannelLogs } -// LastWrittenMsg returns the last message queued to the server -func (mb *MockBackend) LastWrittenMsg() courier.Msg { - if len(mb.writtenMsgs) == 0 { - return nil - } - return mb.writtenMsgs[len(mb.writtenMsgs)-1] -} - -// LastWrittenChannelEvent returns the last event written to the server -func (mb *MockBackend) LastWrittenChannelEvent() courier.ChannelEvent { - if len(mb.writtenChannelEvents) == 0 { - return nil - } - return mb.writtenChannelEvents[len(mb.writtenChannelEvents)-1] -} - -// LastWrittenMsgStatus returns the last status written to the server -func (mb *MockBackend) LastWrittenMsgStatus() courier.MsgStatus { - if len(mb.writtenMsgStatuses) == 0 { - return nil - } - return mb.writtenMsgStatuses[len(mb.writtenMsgStatuses)-1] -} - -// GetLastContactName returns the contact name set on the last msg or channel event written -func (mb *MockBackend) GetLastContactName() string { +// LastContactName returns the contact name set on the last msg or channel event written +func (mb *MockBackend) LastContactName() string { return mb.lastContactName } @@ -132,7 +110,7 @@ func (mb *MockBackend) PushOutgoingMsg(msg courier.Msg) { mb.mutex.Lock() defer mb.mutex.Unlock() - mb.poppedOutgoingMsgs = append(mb.poppedOutgoingMsgs, msg) + mb.outgoingMsgs = append(mb.outgoingMsgs, msg) } // PopNextOutgoingMsg returns the next message that should be sent, or nil if there are none to send @@ -140,9 +118,9 @@ func (mb *MockBackend) PopNextOutgoingMsg(ctx context.Context) (courier.Msg, err mb.mutex.Lock() defer mb.mutex.Unlock() - if len(mb.poppedOutgoingMsgs) > 0 { - msg, rest := mb.poppedOutgoingMsgs[0], mb.poppedOutgoingMsgs[1:] - mb.poppedOutgoingMsgs = rest + if len(mb.outgoingMsgs) > 0 { + msg, rest := mb.outgoingMsgs[0], mb.outgoingMsgs[1:] + mb.outgoingMsgs = rest return msg, nil } @@ -332,11 +310,6 @@ func (mb *MockBackend) Reset() { mb.writtenChannelLogs = nil } -// LenQueuedMsgs Get the length of queued msgs -func (mb *MockBackend) LenQueuedMsgs() int { - return len(mb.writtenMsgs) -} - // CheckExternalIDSeen checks if external ID has been seen in a period func (mb *MockBackend) CheckExternalIDSeen(msg courier.Msg) courier.Msg { m := msg.(*mockMsg) From 9949a264d8e64ba18ab0771b620bc7b48e7078dc Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Thu, 8 Sep 2022 12:50:56 +0200 Subject: [PATCH 145/294] Adjust to use the cache by address correctly --- backends/rapidpro/channel.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/rapidpro/channel.go b/backends/rapidpro/channel.go index 1f7f6e086..565178670 100644 --- a/backends/rapidpro/channel.go +++ b/backends/rapidpro/channel.go @@ -169,7 +169,7 @@ func getChannelByAddress(ctx context.Context, db *sqlx.DB, channelType courier.C } // we found it in the db, cache it locally - cacheChannel(channel) + cacheChannelByAddress(channel) return channel, nil } From 855e10e03919126c461b72e3b96df1f9caa16f0d Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 8 Sep 2022 09:43:41 -0500 Subject: [PATCH 146/294] Update CHANGELOG.md for v7.5.24 --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e47c4b334..678bf9153 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +v7.5.24 +---------- + * Adjust to use the cache by address correctly + * Rework handler tests to assert more state by default + * Remove duplicate status writes + * Append channel log UUIDs on status writes + * Set log UUID on incoming messages and channel events + * Use go 1.19 + * Fix some linter warnings + v7.5.23 ---------- * Support channels receiving embedded attachments and use with thinq handler From 56a637d003a2e0744e31f8a701d8d5359a638c37 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 8 Sep 2022 09:45:28 -0500 Subject: [PATCH 147/294] Fix comment on handler test --- handlers/test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/test.go b/handlers/test.go index f95502586..d32f537b6 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -375,7 +375,7 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri } if tc.ExpectedMsgStatus != "" { - // TODO fix duplicate statuses + // TODO find better way to test statuses because some channels (e.g. infobip) can create multiple statuses in one call require.Greater(len(mb.WrittenMsgStatuses()), 0, "expected a msg status to be written") status := mb.WrittenMsgStatuses()[len(mb.WrittenMsgStatuses())-1] From 74b97f82deaa9d71e1be5bc5817bc2419c6b7296 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 8 Sep 2022 14:39:52 -0500 Subject: [PATCH 148/294] Implement redaction during sending and add testing --- .../africastalking/africastalking_test.go | 4 +-- handlers/arabiacell/arabiacell_test.go | 2 +- handlers/base.go | 29 ++++++++++++++--- handlers/blackmyna/blackmyna.go | 6 ++++ handlers/blackmyna/blackmyna_test.go | 2 +- handlers/bongolive/bongolive_test.go | 2 +- handlers/burstsms/burstsms.go | 6 ++++ handlers/burstsms/burstsms_test.go | 2 +- handlers/chikka/chikka_test.go | 2 +- handlers/clickatell/clickatell_test.go | 2 +- handlers/clickmobile/clickmobile_test.go | 2 +- handlers/clicksend/clicksend.go | 6 ++++ handlers/clicksend/clicksend_test.go | 2 +- handlers/dart/dart_test.go | 2 +- handlers/discord/discord.go | 3 +- handlers/discord/discord_test.go | 4 +-- handlers/dmark/dmark_test.go | 2 +- handlers/external/external_test.go | 32 +++++++++---------- handlers/facebook/facebook_test.go | 2 +- handlers/facebookapp/facebookapp.go | 10 +++--- handlers/facebookapp/facebookapp_test.go | 14 ++++---- handlers/firebase/firebase.go | 2 +- handlers/firebase/firebase_test.go | 4 +-- handlers/freshchat/freshchat_test.go | 2 +- handlers/globe/globe.go | 2 +- handlers/globe/globe_test.go | 2 +- .../highconnection/highconnection_test.go | 2 +- handlers/hormuud/hormuud_test.go | 4 +-- handlers/i2sms/i2sms.go | 9 +++++- handlers/i2sms/i2sms_test.go | 2 +- handlers/infobip/infobip.go | 6 ++++ handlers/infobip/infobip_test.go | 4 +-- handlers/jasmin/jasmin_test.go | 5 +-- handlers/jiochat/jiochat_test.go | 3 +- handlers/junebug/junebug.go | 7 ++++ handlers/junebug/junebug_test.go | 4 +-- handlers/kaleyra/kaleyra_test.go | 2 +- handlers/kannel/kannel_test.go | 4 +-- handlers/line/line_test.go | 2 +- handlers/m3tech/m3tech_test.go | 2 +- handlers/macrokiosk/macrokiosk_test.go | 2 +- handlers/mblox/mblox_test.go | 2 +- handlers/messangi/messangi_test.go | 2 +- handlers/mtarget/mtarget_test.go | 2 +- handlers/nexmo/nexmo.go | 2 +- handlers/nexmo/nexmo_test.go | 2 +- handlers/novo/novo_test.go | 2 +- handlers/playmobile/playmobile.go | 6 ++++ handlers/playmobile/playmobile_test.go | 2 +- handlers/plivo/plivo.go | 6 ++++ handlers/plivo/plivo_test.go | 2 +- handlers/redrabbit/redrabbit_test.go | 2 +- handlers/rocketchat/rocketchat_test.go | 2 +- handlers/shaqodoon/shaqodoon_test.go | 2 +- handlers/slack/slack.go | 2 +- handlers/slack/slack_test.go | 4 +-- handlers/smscentral/smscentral_test.go | 2 +- handlers/start/start.go | 6 ++++ handlers/start/start_test.go | 2 +- handlers/telegram/telegram_test.go | 2 +- handlers/telesom/telesom_test.go | 2 +- handlers/test.go | 24 ++++++++++++-- handlers/thinq/thinq.go | 6 ++++ handlers/thinq/thinq_test.go | 2 +- handlers/twiml/twiml.go | 9 ++++-- handlers/twiml/twiml_test.go | 12 +++---- handlers/twitter/twitter_test.go | 2 +- handlers/utils.go | 12 ++++--- handlers/viber/viber_test.go | 6 ++-- handlers/vk/vk_test.go | 2 +- handlers/wavy/wavy_test.go | 2 +- handlers/wechat/wechat_test.go | 2 +- handlers/whatsapp/whatsapp_test.go | 10 +++--- handlers/yo/yo_test.go | 2 +- handlers/zenvia/zenvia_test.go | 4 +-- handlers/zenviaold/zenviaold.go | 5 +++ handlers/zenviaold/zenviaold_test.go | 2 +- sender.go | 12 +++++-- server.go | 14 ++------ 79 files changed, 251 insertions(+), 137 deletions(-) diff --git a/handlers/africastalking/africastalking_test.go b/handlers/africastalking/africastalking_test.go index 97559b319..f58cfdc1d 100644 --- a/handlers/africastalking/africastalking_test.go +++ b/handlers/africastalking/africastalking_test.go @@ -190,6 +190,6 @@ func TestSending(t *testing.T) { configIsShared: true, }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) - RunChannelSendTestCases(t, sharedChannel, newHandler(), sharedSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"KEY"}, nil) + RunChannelSendTestCases(t, sharedChannel, newHandler(), sharedSendTestCases, []string{"KEY"}, nil) } diff --git a/handlers/arabiacell/arabiacell_test.go b/handlers/arabiacell/arabiacell_test.go index 372e47308..40d7cd5d0 100644 --- a/handlers/arabiacell/arabiacell_test.go +++ b/handlers/arabiacell/arabiacell_test.go @@ -112,5 +112,5 @@ func TestSending(t *testing.T) { configServiceID: "service1", configChargingLevel: "0", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"pass1"}, nil) } diff --git a/handlers/base.go b/handlers/base.go index c9afb581c..f07d061f2 100644 --- a/handlers/base.go +++ b/handlers/base.go @@ -8,6 +8,8 @@ import ( "github.com/nyaruka/courier" ) +var defaultRedactConfigKeys = []string{courier.ConfigAuthToken, courier.ConfigAPIKey, courier.ConfigSecret, courier.ConfigPassword, courier.ConfigSendAuthorization} + // BaseHandler is the base class for most handlers, it just stored the server, name and channel type for the handler type BaseHandler struct { channelType courier.ChannelType @@ -15,16 +17,22 @@ type BaseHandler struct { server courier.Server backend courier.Backend useChannelRouteUUID bool + redactConfigKeys []string } // NewBaseHandler returns a newly constructed BaseHandler with the passed in parameters func NewBaseHandler(channelType courier.ChannelType, name string) BaseHandler { - return NewBaseHandlerWithParams(channelType, name, true) + return NewBaseHandlerWithParams(channelType, name, true, defaultRedactConfigKeys) } // NewBaseHandlerWithParams returns a newly constructed BaseHandler with the passed in parameters -func NewBaseHandlerWithParams(channelType courier.ChannelType, name string, useChannelRouteUUID bool) BaseHandler { - return BaseHandler{channelType: channelType, name: name, useChannelRouteUUID: useChannelRouteUUID} +func NewBaseHandlerWithParams(channelType courier.ChannelType, name string, useChannelRouteUUID bool, redactConfigKeys []string) BaseHandler { + return BaseHandler{ + channelType: channelType, + name: name, + useChannelRouteUUID: useChannelRouteUUID, + redactConfigKeys: redactConfigKeys, + } } // SetServer can be used to change the server on a BaseHandler @@ -58,7 +66,20 @@ func (h *BaseHandler) UseChannelRouteUUID() bool { return h.useChannelRouteUUID } -func (h *BaseHandler) RedactValues(courier.Channel) []string { return nil } +func (h *BaseHandler) RedactValues(ch courier.Channel) []string { + if ch == nil { + return nil + } + + vals := make([]string, 0, len(h.redactConfigKeys)) + for _, k := range h.redactConfigKeys { + v := ch.StringConfigForKey(k, "") + if v != "" { + vals = append(vals, v) + } + } + return vals +} // GetChannel returns the channel func (h *BaseHandler) GetChannel(ctx context.Context, r *http.Request) (courier.Channel, error) { diff --git a/handlers/blackmyna/blackmyna.go b/handlers/blackmyna/blackmyna.go index 0bcaa7377..69f1f37c0 100644 --- a/handlers/blackmyna/blackmyna.go +++ b/handlers/blackmyna/blackmyna.go @@ -144,3 +144,9 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } + +func (h *handler) RedactValues(ch courier.Channel) []string { + return []string{ + handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + } +} diff --git a/handlers/blackmyna/blackmyna_test.go b/handlers/blackmyna/blackmyna_test.go index 5158246d5..58d281ec3 100644 --- a/handlers/blackmyna/blackmyna_test.go +++ b/handlers/blackmyna/blackmyna_test.go @@ -146,5 +146,5 @@ func TestSending(t *testing.T) { courier.ConfigAPIKey: "KEY", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{BasicAuth("Username", "Password")}, nil) } diff --git a/handlers/bongolive/bongolive_test.go b/handlers/bongolive/bongolive_test.go index b08de58e9..03842bbf3 100644 --- a/handlers/bongolive/bongolive_test.go +++ b/handlers/bongolive/bongolive_test.go @@ -150,5 +150,5 @@ func TestSending(t *testing.T) { courier.ConfigUsername: "user1", courier.ConfigPassword: "pass1", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"pass1"}, nil) } diff --git a/handlers/burstsms/burstsms.go b/handlers/burstsms/burstsms.go index c8b7cb4e9..cd68021e3 100644 --- a/handlers/burstsms/burstsms.go +++ b/handlers/burstsms/burstsms.go @@ -108,3 +108,9 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } + +func (h *handler) RedactValues(ch courier.Channel) []string { + return []string{ + handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + } +} diff --git a/handlers/burstsms/burstsms_test.go b/handlers/burstsms/burstsms_test.go index 556bb25ec..c41bca01e 100644 --- a/handlers/burstsms/burstsms_test.go +++ b/handlers/burstsms/burstsms_test.go @@ -115,5 +115,5 @@ func TestSending(t *testing.T) { courier.ConfigUsername: "user1", courier.ConfigPassword: "pass1", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{BasicAuth("user1", "pass1")}, nil) } diff --git a/handlers/chikka/chikka_test.go b/handlers/chikka/chikka_test.go index aec9ee56d..3b60b8772 100644 --- a/handlers/chikka/chikka_test.go +++ b/handlers/chikka/chikka_test.go @@ -240,5 +240,5 @@ func TestSending(t *testing.T) { courier.ConfigUsername: "Username", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"Password"}, nil) } diff --git a/handlers/clickatell/clickatell_test.go b/handlers/clickatell/clickatell_test.go index e59870371..43784a5d1 100644 --- a/handlers/clickatell/clickatell_test.go +++ b/handlers/clickatell/clickatell_test.go @@ -83,7 +83,7 @@ func TestSending(t *testing.T) { courier.ConfigAPIKey: "API-KEY", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"API-KEY"}, nil) } var testChannels = []courier.Channel{ diff --git a/handlers/clickmobile/clickmobile_test.go b/handlers/clickmobile/clickmobile_test.go index 819703782..cd86d2cdf 100644 --- a/handlers/clickmobile/clickmobile_test.go +++ b/handlers/clickmobile/clickmobile_test.go @@ -211,5 +211,5 @@ func TestSending(t *testing.T) { // mock time so we can have predictable MD5 hashes dates.SetNowSource(dates.NewFixedNowSource(time.Date(2018, 4, 11, 18, 24, 30, 123456000, time.UTC))) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"Password"}, nil) } diff --git a/handlers/clicksend/clicksend.go b/handlers/clicksend/clicksend.go index dfca3593d..c38f1754b 100644 --- a/handlers/clicksend/clicksend.go +++ b/handlers/clicksend/clicksend.go @@ -118,3 +118,9 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } + +func (h *handler) RedactValues(ch courier.Channel) []string { + return []string{ + handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + } +} diff --git a/handlers/clicksend/clicksend_test.go b/handlers/clicksend/clicksend_test.go index 4c4796bdc..36f646e78 100644 --- a/handlers/clicksend/clicksend_test.go +++ b/handlers/clicksend/clicksend_test.go @@ -174,5 +174,5 @@ func TestSending(t *testing.T) { }, ) - RunChannelSendTestCases(t, defaultChannel, newHandler(), sendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), sendTestCases, []string{BasicAuth("Aladdin", "open sesame")}, nil) } diff --git a/handlers/dart/dart_test.go b/handlers/dart/dart_test.go index b9315ed8a..d4f79030f 100644 --- a/handlers/dart/dart_test.go +++ b/handlers/dart/dart_test.go @@ -171,5 +171,5 @@ func TestSending(t *testing.T) { courier.ConfigPassword: "Password", }) - RunChannelSendTestCases(t, defaultDAChannel, NewHandler("DA", "Dartmedia", sendURL, maxMsgLength), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultDAChannel, NewHandler("DA", "Dartmedia", sendURL, maxMsgLength), defaultSendTestCases, []string{"Password"}, nil) } diff --git a/handlers/discord/discord.go b/handlers/discord/discord.go index d7f2b2d36..68f3284f3 100644 --- a/handlers/discord/discord.go +++ b/handlers/discord/discord.go @@ -8,9 +8,8 @@ import ( "io" "net/http" "net/url" - "time" - "strings" + "time" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" diff --git a/handlers/discord/discord_test.go b/handlers/discord/discord_test.go index 1d0d1d464..176b0180e 100644 --- a/handlers/discord/discord_test.go +++ b/handlers/discord/discord_test.go @@ -19,7 +19,7 @@ func BenchmarkHandler(b *testing.B) { } var testChannels = []courier.Channel{ - test.NewMockChannel("bac782c2-7aeb-4389-92f5-97887744f573", "DS", "discord", "US", map[string]interface{}{}), + test.NewMockChannel("bac782c2-7aeb-4389-92f5-97887744f573", "DS", "discord", "US", map[string]interface{}{courier.ConfigSendAuthorization: "sesame"}), } var testCases = []ChannelHandleTestCase{ @@ -119,5 +119,5 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } func TestSending(t *testing.T) { - RunChannelSendTestCases(t, testChannels[0], newHandler(), sendTestCases, nil) + RunChannelSendTestCases(t, testChannels[0], newHandler(), sendTestCases, []string{"sesame"}, nil) } diff --git a/handlers/dmark/dmark_test.go b/handlers/dmark/dmark_test.go index 9a45e7980..ff6d6a2a7 100644 --- a/handlers/dmark/dmark_test.go +++ b/handlers/dmark/dmark_test.go @@ -139,5 +139,5 @@ func TestSending(t *testing.T) { courier.ConfigAuthToken: "Authy", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"Authy"}, nil) } diff --git a/handlers/external/external_test.go b/handlers/external/external_test.go index fa2b73e39..f686c8951 100644 --- a/handlers/external/external_test.go +++ b/handlers/external/external_test.go @@ -726,16 +726,16 @@ func TestSending(t *testing.T) { courier.ConfigSendMethod: http.MethodPut, }) - RunChannelSendTestCases(t, getChannel, newHandler(), getSendTestCases, nil) - RunChannelSendTestCases(t, getSmartChannel, newHandler(), getSendTestCases, nil) - RunChannelSendTestCases(t, getSmartChannel, newHandler(), getSendSmartEncodingTestCases, nil) - RunChannelSendTestCases(t, postChannel, newHandler(), postSendTestCases, nil) - RunChannelSendTestCases(t, postChannelCustomContentType, newHandler(), postSendCustomContentTypeTestCases, nil) - RunChannelSendTestCases(t, postSmartChannel, newHandler(), postSendTestCases, nil) - RunChannelSendTestCases(t, postSmartChannel, newHandler(), postSendSmartEncodingTestCases, nil) - RunChannelSendTestCases(t, jsonChannel, newHandler(), jsonSendTestCases, nil) - RunChannelSendTestCases(t, xmlChannel, newHandler(), xmlSendTestCases, nil) - RunChannelSendTestCases(t, xmlChannelWithResponseContent, newHandler(), xmlSendWithResponseContentTestCases, nil) + RunChannelSendTestCases(t, getChannel, newHandler(), getSendTestCases, nil, nil) + RunChannelSendTestCases(t, getSmartChannel, newHandler(), getSendTestCases, nil, nil) + RunChannelSendTestCases(t, getSmartChannel, newHandler(), getSendSmartEncodingTestCases, nil, nil) + RunChannelSendTestCases(t, postChannel, newHandler(), postSendTestCases, nil, nil) + RunChannelSendTestCases(t, postChannelCustomContentType, newHandler(), postSendCustomContentTypeTestCases, nil, nil) + RunChannelSendTestCases(t, postSmartChannel, newHandler(), postSendTestCases, nil, nil) + RunChannelSendTestCases(t, postSmartChannel, newHandler(), postSendSmartEncodingTestCases, nil, nil) + RunChannelSendTestCases(t, jsonChannel, newHandler(), jsonSendTestCases, nil, nil) + RunChannelSendTestCases(t, xmlChannel, newHandler(), xmlSendTestCases, nil, nil) + RunChannelSendTestCases(t, xmlChannelWithResponseContent, newHandler(), xmlSendWithResponseContentTestCases, nil, nil) var getChannel30IntLength = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ @@ -769,10 +769,10 @@ func TestSending(t *testing.T) { courier.ConfigSendHeaders: map[string]interface{}{"Authorization": "Token ABCDEF", "foo": "bar"}, }) - RunChannelSendTestCases(t, getChannel30IntLength, newHandler(), longSendTestCases, nil) - RunChannelSendTestCases(t, getChannel30StrLength, newHandler(), longSendTestCases, nil) - RunChannelSendTestCases(t, jsonChannel30IntLength, newHandler(), jsonLongSendTestCases, nil) - RunChannelSendTestCases(t, xmlChannel30IntLength, newHandler(), xmlLongSendTestCases, nil) + RunChannelSendTestCases(t, getChannel30IntLength, newHandler(), longSendTestCases, nil, nil) + RunChannelSendTestCases(t, getChannel30StrLength, newHandler(), longSendTestCases, nil, nil) + RunChannelSendTestCases(t, jsonChannel30IntLength, newHandler(), jsonLongSendTestCases, nil, nil) + RunChannelSendTestCases(t, xmlChannel30IntLength, newHandler(), xmlLongSendTestCases, nil, nil) var nationalChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ @@ -780,7 +780,7 @@ func TestSending(t *testing.T) { "use_national": true, courier.ConfigSendMethod: http.MethodGet}) - RunChannelSendTestCases(t, nationalChannel, newHandler(), nationalGetSendTestCases, nil) + RunChannelSendTestCases(t, nationalChannel, newHandler(), nationalGetSendTestCases, nil, nil) var jsonChannelWithSendAuthorization = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", map[string]interface{}{ @@ -790,6 +790,6 @@ func TestSending(t *testing.T) { courier.ConfigSendMethod: http.MethodPost, courier.ConfigSendAuthorization: "Token ABCDEF", }) - RunChannelSendTestCases(t, jsonChannelWithSendAuthorization, newHandler(), jsonSendTestCases, nil) + RunChannelSendTestCases(t, jsonChannelWithSendAuthorization, newHandler(), jsonSendTestCases, []string{"Token ABCDEF"}, nil) } diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index 6c93b2fcb..33d3bda65 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -860,5 +860,5 @@ func TestSending(t *testing.T) { maxMsgLength = 100 var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "FB", "2020", "US", map[string]interface{}{courier.ConfigAuthToken: "access_token"}) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"access_token"}, nil) } diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 45b8f488b..707b7ff32 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -69,7 +69,7 @@ var waIgnoreStatuses = map[string]bool{ } func newHandler(channelType courier.ChannelType, name string, useUUIDRoutes bool) courier.ChannelHandler { - return &handler{handlers.NewBaseHandlerWithParams(channelType, name, useUUIDRoutes)} + return &handler{handlers.NewBaseHandlerWithParams(channelType, name, useUUIDRoutes, []string{courier.ConfigAuthToken})} } func init() { @@ -266,11 +266,9 @@ type moPayload struct { } func (h *handler) RedactValues(ch courier.Channel) []string { - return []string{ - h.Server().Config().FacebookApplicationSecret, - h.Server().Config().FacebookWebhookSecret, - h.Server().Config().WhatsappAdminSystemUserToken, - } + vals := h.BaseHandler.RedactValues(ch) + vals = append(vals, h.Server().Config().FacebookApplicationSecret, h.Server().Config().FacebookWebhookSecret, h.Server().Config().WhatsappAdminSystemUserToken) + return vals } // GetChannel returns the channel diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 0ed63d8e7..6562cbe55 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -1316,9 +1316,11 @@ func TestSending(t *testing.T) { var ChannelIG = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "IG", "12345", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}) var ChannelWAC = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WAC", "12345_ID", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}) - RunChannelSendTestCases(t, ChannelFBA, newHandler("FBA", "Facebook", false), SendTestCasesFBA, nil) - RunChannelSendTestCases(t, ChannelIG, newHandler("IG", "Instagram", false), SendTestCasesIG, nil) - RunChannelSendTestCases(t, ChannelWAC, newHandler("WAC", "Cloud API WhatsApp", false), SendTestCasesWAC, nil) + checkRedacted := []string{"wac_admin_system_user_token", "missing_facebook_app_secret", "missing_facebook_webhook_secret", "a123"} + + RunChannelSendTestCases(t, ChannelFBA, newHandler("FBA", "Facebook", false), SendTestCasesFBA, checkRedacted, nil) + RunChannelSendTestCases(t, ChannelIG, newHandler("IG", "Instagram", false), SendTestCasesIG, checkRedacted, nil) + RunChannelSendTestCases(t, ChannelWAC, newHandler("WAC", "Cloud API WhatsApp", false), SendTestCasesWAC, checkRedacted, nil) } func TestSigning(t *testing.T) { @@ -1352,19 +1354,19 @@ func newServer(backend courier.Backend) courier.Server { func TestBuildMediaRequest(t *testing.T) { mb := test.NewMockBackend() s := newServer(mb) - wacHandler := &handler{NewBaseHandlerWithParams(courier.ChannelType("WAC"), "WhatsApp Cloud", false)} + wacHandler := &handler{NewBaseHandlerWithParams(courier.ChannelType("WAC"), "WhatsApp Cloud", false, nil)} wacHandler.Initialize(s) req, _ := wacHandler.BuildDownloadMediaRequest(context.Background(), mb, testChannelsWAC[0], "https://example.org/v1/media/41") assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, "Bearer wac_admin_system_user_token", req.Header.Get("Authorization")) - fbaHandler := &handler{NewBaseHandlerWithParams(courier.ChannelType("FBA"), "Facebook", false)} + fbaHandler := &handler{NewBaseHandlerWithParams(courier.ChannelType("FBA"), "Facebook", false, nil)} fbaHandler.Initialize(s) req, _ = fbaHandler.BuildDownloadMediaRequest(context.Background(), mb, testChannelsFBA[0], "https://example.org/v1/media/41") assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, http.Header{}, req.Header) - igHandler := &handler{NewBaseHandlerWithParams(courier.ChannelType("IG"), "Instagram", false)} + igHandler := &handler{NewBaseHandlerWithParams(courier.ChannelType("IG"), "Instagram", false, nil)} igHandler.Initialize(s) req, _ = igHandler.BuildDownloadMediaRequest(context.Background(), mb, testChannelsFBA[0], "https://example.org/v1/media/41") assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) diff --git a/handlers/firebase/firebase.go b/handlers/firebase/firebase.go index a02fce59e..322a5af1d 100644 --- a/handlers/firebase/firebase.go +++ b/handlers/firebase/firebase.go @@ -35,7 +35,7 @@ type handler struct { } func newHandler() courier.ChannelHandler { - return &handler{handlers.NewBaseHandler(courier.ChannelType("FCM"), "Firebase")} + return &handler{handlers.NewBaseHandlerWithParams(courier.ChannelType("FCM"), "Firebase", true, []string{configKey})} } func (h *handler) Initialize(s courier.Server) error { diff --git a/handlers/firebase/firebase_test.go b/handlers/firebase/firebase_test.go index 32236437f..ee4c0f37b 100644 --- a/handlers/firebase/firebase_test.go +++ b/handlers/firebase/firebase_test.go @@ -192,6 +192,6 @@ var sendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - RunChannelSendTestCases(t, testChannels[0], newHandler(), sendTestCases, nil) - RunChannelSendTestCases(t, testChannels[1], newHandler(), notificationSendTestCases, nil) + RunChannelSendTestCases(t, testChannels[0], newHandler(), sendTestCases, []string{"FCMKey"}, nil) + RunChannelSendTestCases(t, testChannels[1], newHandler(), notificationSendTestCases, []string{"FCMKey"}, nil) } diff --git a/handlers/freshchat/freshchat_test.go b/handlers/freshchat/freshchat_test.go index b3d2ea16b..220f8029c 100644 --- a/handlers/freshchat/freshchat_test.go +++ b/handlers/freshchat/freshchat_test.go @@ -131,5 +131,5 @@ func TestSending(t *testing.T) { "secret": cert, "auth_token": "enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ=", }) - RunChannelSendTestCases(t, defaultChannel, newHandler("FC", "FreshChat", false), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler("FC", "FreshChat", false), defaultSendTestCases, []string{cert, "enYtdXNlcm5hbWU6enYtcGFzc3dvcmQ="}, nil) } diff --git a/handlers/globe/globe.go b/handlers/globe/globe.go index f08e55d4f..7ea85848f 100644 --- a/handlers/globe/globe.go +++ b/handlers/globe/globe.go @@ -33,7 +33,7 @@ type handler struct { } func newHandler() courier.ChannelHandler { - return &handler{handlers.NewBaseHandler(courier.ChannelType("GL"), "Globe Labs")} + return &handler{handlers.NewBaseHandlerWithParams(courier.ChannelType("GL"), "Globe Labs", true, []string{configPassphrase, configAppSecret})} } // Initialize is called by the engine once everything is loaded diff --git a/handlers/globe/globe_test.go b/handlers/globe/globe_test.go index 889b16b7c..01b381235 100644 --- a/handlers/globe/globe_test.go +++ b/handlers/globe/globe_test.go @@ -222,5 +222,5 @@ func TestSending(t *testing.T) { }, ) - RunChannelSendTestCases(t, defaultChannel, newHandler(), sendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), sendTestCases, []string{"mysecret", "opensesame"}, nil) } diff --git a/handlers/highconnection/highconnection_test.go b/handlers/highconnection/highconnection_test.go index 3263443c1..0fdefc65e 100644 --- a/handlers/highconnection/highconnection_test.go +++ b/handlers/highconnection/highconnection_test.go @@ -196,5 +196,5 @@ func TestSending(t *testing.T) { courier.ConfigUsername: "Username", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"Password"}, nil) } diff --git a/handlers/hormuud/hormuud_test.go b/handlers/hormuud/hormuud_test.go index 6ff3b34fa..b96e67620 100644 --- a/handlers/hormuud/hormuud_test.go +++ b/handlers/hormuud/hormuud_test.go @@ -149,9 +149,9 @@ func TestSending(t *testing.T) { }, ) - RunChannelSendTestCases(t, defaultChannel, newHandler(), sendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), sendTestCases, []string{"sesame"}, nil) tokenURL = server.URL + "?invalid=true" - RunChannelSendTestCases(t, defaultChannel, newHandler(), tokenTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), tokenTestCases, []string{"sesame"}, nil) } diff --git a/handlers/i2sms/i2sms.go b/handlers/i2sms/i2sms.go index ae1e3824d..702301543 100644 --- a/handlers/i2sms/i2sms.go +++ b/handlers/i2sms/i2sms.go @@ -31,7 +31,7 @@ type handler struct { } func newHandler() courier.ChannelHandler { - return &handler{handlers.NewBaseHandler(courier.ChannelType("I2"), "I2SMS")} + return &handler{handlers.NewBaseHandlerWithParams(courier.ChannelType("I2"), "I2SMS", true, []string{courier.ConfigPassword, configChannelHash})} } // Initialize is called by the engine once everything is loaded @@ -143,6 +143,13 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } +func (h *handler) RedactValues(ch courier.Channel) []string { + return []string{ + handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + ch.StringConfigForKey(configChannelHash, ""), + } +} + // WriteMsgSuccessResponse writes a success response for the messages, i2SMS expects an empty body in our response func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error { w.Header().Add("Content-type", "text/plain") diff --git a/handlers/i2sms/i2sms_test.go b/handlers/i2sms/i2sms_test.go index 949b4b0de..5d597d9d7 100644 --- a/handlers/i2sms/i2sms_test.go +++ b/handlers/i2sms/i2sms_test.go @@ -104,5 +104,5 @@ func TestSending(t *testing.T) { courier.ConfigPassword: "pass1", configChannelHash: "hash123", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{BasicAuth("user1", "pass1"), "hash123"}, nil) } diff --git a/handlers/infobip/infobip.go b/handlers/infobip/infobip.go index de56bb9a0..385f78a7f 100644 --- a/handlers/infobip/infobip.go +++ b/handlers/infobip/infobip.go @@ -247,6 +247,12 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } +func (h *handler) RedactValues(ch courier.Channel) []string { + return []string{ + handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + } +} + // { // "bulkId":"BULK-ID-123-xyz", // "messages":[ diff --git a/handlers/infobip/infobip_test.go b/handlers/infobip/infobip_test.go index f37d9f610..3503628e0 100644 --- a/handlers/infobip/infobip_test.go +++ b/handlers/infobip/infobip_test.go @@ -408,7 +408,7 @@ func TestSending(t *testing.T) { courier.ConfigUsername: "Username", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{BasicAuth("Username", "Password")}, nil) var transChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "IB", "2020", "US", map[string]interface{}{ @@ -417,5 +417,5 @@ func TestSending(t *testing.T) { configTransliteration: "COLOMBIAN", }) - RunChannelSendTestCases(t, transChannel, newHandler(), transSendTestCases, nil) + RunChannelSendTestCases(t, transChannel, newHandler(), transSendTestCases, []string{BasicAuth("Username", "Password")}, nil) } diff --git a/handlers/jasmin/jasmin_test.go b/handlers/jasmin/jasmin_test.go index 20e520e86..b2c4303a3 100644 --- a/handlers/jasmin/jasmin_test.go +++ b/handlers/jasmin/jasmin_test.go @@ -161,7 +161,8 @@ func TestSending(t *testing.T) { var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JS", "2020", "US", map[string]interface{}{ "password": "Password", - "username": "Username"}) + "username": "Username", + }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"Password"}, nil) } diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index 6e0862aa8..18e8fa9c1 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -409,5 +409,6 @@ func setupBackend(mb *test.MockBackend) { func TestSending(t *testing.T) { maxMsgLength = 160 var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JC", "2020", "US", map[string]interface{}{configAppSecret: "secret", configAppID: "app-id"}) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, setupBackend) + + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"secret"}, setupBackend) } diff --git a/handlers/junebug/junebug.go b/handlers/junebug/junebug.go index 468258acd..223c3749f 100644 --- a/handlers/junebug/junebug.go +++ b/handlers/junebug/junebug.go @@ -218,3 +218,10 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann status.SetStatus(courier.MsgWired) return status, nil } + +func (h *handler) RedactValues(ch courier.Channel) []string { + return []string{ + handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + ch.StringConfigForKey(courier.ConfigSecret, ""), + } +} diff --git a/handlers/junebug/junebug_test.go b/handlers/junebug/junebug_test.go index 2077c4d4b..32efd3291 100644 --- a/handlers/junebug/junebug_test.go +++ b/handlers/junebug/junebug_test.go @@ -217,6 +217,6 @@ var authenticatedSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - RunChannelSendTestCases(t, testChannel, newHandler(), sendTestCases, nil) - RunChannelSendTestCases(t, authenticatedTestChannel, newHandler(), authenticatedSendTestCases, nil) + RunChannelSendTestCases(t, testChannel, newHandler(), sendTestCases, []string{BasicAuth("user1", "pass1"), "sesame"}, nil) + RunChannelSendTestCases(t, authenticatedTestChannel, newHandler(), authenticatedSendTestCases, []string{BasicAuth("user1", "pass1"), "sesame"}, nil) } diff --git a/handlers/kaleyra/kaleyra_test.go b/handlers/kaleyra/kaleyra_test.go index a22f7fa29..a574c5397 100644 --- a/handlers/kaleyra/kaleyra_test.go +++ b/handlers/kaleyra/kaleyra_test.go @@ -239,7 +239,7 @@ func TestSending(t *testing.T) { })) mockedSendTestCases := mockAttachmentURLs(mediaServer, sendTestCases) - RunChannelSendTestCases(t, testChannels[0], newHandler(), mockedSendTestCases, nil) + RunChannelSendTestCases(t, testChannels[0], newHandler(), mockedSendTestCases, []string{"123456"}, nil) } var urlTestCases = []struct { diff --git a/handlers/kannel/kannel_test.go b/handlers/kannel/kannel_test.go index 2ba76a374..4378fe8b6 100644 --- a/handlers/kannel/kannel_test.go +++ b/handlers/kannel/kannel_test.go @@ -142,6 +142,6 @@ func TestSending(t *testing.T) { "dlr_mask": "3", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) - RunChannelSendTestCases(t, nationalChannel, newHandler(), nationalSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"Password"}, nil) + RunChannelSendTestCases(t, nationalChannel, newHandler(), nationalSendTestCases, []string{"Password"}, nil) } diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index fbfe0ab5d..8e25bcf0e 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -519,7 +519,7 @@ func TestSending(t *testing.T) { }, ) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, setupMedia) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"AccessToken"}, setupMedia) } func TestBuildMediaRequest(t *testing.T) { diff --git a/handlers/m3tech/m3tech_test.go b/handlers/m3tech/m3tech_test.go index 51ca02fe6..58561d80f 100644 --- a/handlers/m3tech/m3tech_test.go +++ b/handlers/m3tech/m3tech_test.go @@ -103,5 +103,5 @@ func TestSending(t *testing.T) { }, ) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"Password"}, nil) } diff --git a/handlers/macrokiosk/macrokiosk_test.go b/handlers/macrokiosk/macrokiosk_test.go index 92008a231..bde14a082 100644 --- a/handlers/macrokiosk/macrokiosk_test.go +++ b/handlers/macrokiosk/macrokiosk_test.go @@ -138,5 +138,5 @@ func TestSending(t *testing.T) { }, ) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"Password"}, nil) } diff --git a/handlers/mblox/mblox_test.go b/handlers/mblox/mblox_test.go index 75a12a9a0..f8cb71044 100644 --- a/handlers/mblox/mblox_test.go +++ b/handlers/mblox/mblox_test.go @@ -164,5 +164,5 @@ func TestSending(t *testing.T) { }, ) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"Password"}, nil) } diff --git a/handlers/messangi/messangi_test.go b/handlers/messangi/messangi_test.go index 98c87a33f..e9f4e2939 100644 --- a/handlers/messangi/messangi_test.go +++ b/handlers/messangi/messangi_test.go @@ -105,5 +105,5 @@ func TestSending(t *testing.T) { "instance_id": 7, "carrier_id": 2, }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"my-private-key"}, nil) } diff --git a/handlers/mtarget/mtarget_test.go b/handlers/mtarget/mtarget_test.go index 2a91e9504..bfe7dbbb5 100644 --- a/handlers/mtarget/mtarget_test.go +++ b/handlers/mtarget/mtarget_test.go @@ -131,5 +131,5 @@ func TestSending(t *testing.T) { }, ) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"Password"}, nil) } diff --git a/handlers/nexmo/nexmo.go b/handlers/nexmo/nexmo.go index 8d164c80e..6573f2a13 100644 --- a/handlers/nexmo/nexmo.go +++ b/handlers/nexmo/nexmo.go @@ -40,7 +40,7 @@ type handler struct { } func newHandler() courier.ChannelHandler { - return &handler{handlers.NewBaseHandler(courier.ChannelType("NX"), "Nexmo")} + return &handler{handlers.NewBaseHandlerWithParams(courier.ChannelType("NX"), "Nexmo", true, []string{configNexmoAPISecret, configNexmoAppPrivateKey})} } // Initialize is called by the engine once everything is loaded diff --git a/handlers/nexmo/nexmo_test.go b/handlers/nexmo/nexmo_test.go index 071366d83..ee95a4050 100644 --- a/handlers/nexmo/nexmo_test.go +++ b/handlers/nexmo/nexmo_test.go @@ -215,5 +215,5 @@ func TestSending(t *testing.T) { configNexmoAppPrivateKey: "nexmo-app-private-key", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"nexmo-api-secret", "nexmo-app-private-key"}, nil) } diff --git a/handlers/novo/novo_test.go b/handlers/novo/novo_test.go index 078960fe5..dfb4b19e9 100644 --- a/handlers/novo/novo_test.go +++ b/handlers/novo/novo_test.go @@ -123,5 +123,5 @@ func TestSending(t *testing.T) { "merchant_secret": "my-merchant-secret", "secret": "sesame", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"my-merchant-secret", "sesame"}, nil) } diff --git a/handlers/playmobile/playmobile.go b/handlers/playmobile/playmobile.go index 4ebf912b2..6a9fe7c02 100644 --- a/handlers/playmobile/playmobile.go +++ b/handlers/playmobile/playmobile.go @@ -206,3 +206,9 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } + +func (h *handler) RedactValues(ch courier.Channel) []string { + return []string{ + handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + } +} diff --git a/handlers/playmobile/playmobile_test.go b/handlers/playmobile/playmobile_test.go index 48de394c1..4c2c5b704 100644 --- a/handlers/playmobile/playmobile_test.go +++ b/handlers/playmobile/playmobile_test.go @@ -186,5 +186,5 @@ func TestSending(t *testing.T) { "base_url": "http://91.204.239.42", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{BasicAuth("Username", "Password")}, nil) } diff --git a/handlers/plivo/plivo.go b/handlers/plivo/plivo.go index e443eb7dc..b3185fa93 100644 --- a/handlers/plivo/plivo.go +++ b/handlers/plivo/plivo.go @@ -189,3 +189,9 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann status.SetStatus(courier.MsgWired) return status, nil } + +func (h *handler) RedactValues(ch courier.Channel) []string { + return []string{ + handlers.BasicAuth(ch.StringConfigForKey(configPlivoAuthID, ""), ch.StringConfigForKey(configPlivoAuthToken, "")), + } +} diff --git a/handlers/plivo/plivo_test.go b/handlers/plivo/plivo_test.go index f86a27b69..ee36efa43 100644 --- a/handlers/plivo/plivo_test.go +++ b/handlers/plivo/plivo_test.go @@ -132,5 +132,5 @@ func TestSending(t *testing.T) { }, ) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{BasicAuth("AuthID", "AuthToken")}, nil) } diff --git a/handlers/redrabbit/redrabbit_test.go b/handlers/redrabbit/redrabbit_test.go index 74c9b6420..2afa17eca 100644 --- a/handlers/redrabbit/redrabbit_test.go +++ b/handlers/redrabbit/redrabbit_test.go @@ -105,5 +105,5 @@ func TestSending(t *testing.T) { }, ) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"Password"}, nil) } diff --git a/handlers/rocketchat/rocketchat_test.go b/handlers/rocketchat/rocketchat_test.go index e71ed1fe1..5517f06e9 100644 --- a/handlers/rocketchat/rocketchat_test.go +++ b/handlers/rocketchat/rocketchat_test.go @@ -146,5 +146,5 @@ var sendTestCases = []handlers.ChannelSendTestCase{ } func TestSending(t *testing.T) { - handlers.RunChannelSendTestCases(t, testChannels[0], newHandler(), sendTestCases, nil) + handlers.RunChannelSendTestCases(t, testChannels[0], newHandler(), sendTestCases, []string{"123456789"}, nil) } diff --git a/handlers/shaqodoon/shaqodoon_test.go b/handlers/shaqodoon/shaqodoon_test.go index 1eb63d32e..33c24f9a8 100644 --- a/handlers/shaqodoon/shaqodoon_test.go +++ b/handlers/shaqodoon/shaqodoon_test.go @@ -89,5 +89,5 @@ func TestSending(t *testing.T) { courier.ConfigPassword: "Password", courier.ConfigUsername: "Username"}) - RunChannelSendTestCases(t, getChannel, newHandler(), getSendTestCases, nil) + RunChannelSendTestCases(t, getChannel, newHandler(), getSendTestCases, []string{"Password"}, nil) } diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index 52b42c947..a390fedda 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -41,7 +41,7 @@ type handler struct { } func newHandler() courier.ChannelHandler { - return &handler{handlers.NewBaseHandler(courier.ChannelType("SL"), "Slack")} + return &handler{handlers.NewBaseHandlerWithParams(courier.ChannelType("SL"), "Slack", true, []string{configBotToken, configUserToken, configValidationToken})} } func (h *handler) Initialize(s courier.Server) error { diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index a2b6cf8e5..d2ac5719d 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -252,7 +252,7 @@ func TestHandler(t *testing.T) { } func TestSending(t *testing.T) { - RunChannelSendTestCases(t, testChannels[0], newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, testChannels[0], newHandler(), defaultSendTestCases, []string{"xoxb-abc123", "one-long-verification-token"}, nil) } func TestSendFiles(t *testing.T) { @@ -260,7 +260,7 @@ func TestSendFiles(t *testing.T) { defer fileServer.Close() fileSendTestCases := mockAttachmentURLs(fileServer, fileSendTestCases) - RunChannelSendTestCases(t, testChannels[0], newHandler(), fileSendTestCases, nil) + RunChannelSendTestCases(t, testChannels[0], newHandler(), fileSendTestCases, []string{"xoxb-abc123", "one-long-verification-token"}, nil) } func TestVerification(t *testing.T) { diff --git a/handlers/smscentral/smscentral_test.go b/handlers/smscentral/smscentral_test.go index 4b5e376aa..5ae501b73 100644 --- a/handlers/smscentral/smscentral_test.go +++ b/handlers/smscentral/smscentral_test.go @@ -106,5 +106,5 @@ func TestSending(t *testing.T) { courier.ConfigUsername: "Username", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"Password"}, nil) } diff --git a/handlers/start/start.go b/handlers/start/start.go index a4157788b..1cba35479 100644 --- a/handlers/start/start.go +++ b/handlers/start/start.go @@ -180,3 +180,9 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } + +func (h *handler) RedactValues(ch courier.Channel) []string { + return []string{ + handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + } +} diff --git a/handlers/start/start_test.go b/handlers/start/start_test.go index b49be77fb..b0381b42c 100644 --- a/handlers/start/start_test.go +++ b/handlers/start/start_test.go @@ -240,5 +240,5 @@ var defaultSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ST", "2020", "UA", map[string]interface{}{"username": "Username", "password": "Password"}) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{BasicAuth("Username", "Password")}, nil) } diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index 1080aaac3..238c6c4a4 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -855,5 +855,5 @@ func TestSending(t *testing.T) { var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TG", "2020", "US", map[string]interface{}{courier.ConfigAuthToken: "auth_token"}) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"auth_token"}, nil) } diff --git a/handlers/telesom/telesom_test.go b/handlers/telesom/telesom_test.go index 8736a368c..c56cf095f 100644 --- a/handlers/telesom/telesom_test.go +++ b/handlers/telesom/telesom_test.go @@ -150,5 +150,5 @@ func TestSending(t *testing.T) { // mock time so we can have predictable MD5 hashes dates.SetNowSource(dates.NewFixedNowSource(time.Date(2018, 4, 11, 18, 24, 30, 123456000, time.UTC))) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"Password", "secret"}, nil) } diff --git a/handlers/test.go b/handlers/test.go index 7689cc034..2b835c4ef 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -182,7 +182,7 @@ func newServer(backend courier.Backend) courier.Server { } // RunChannelSendTestCases runs all the passed in test cases against the channel -func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler courier.ChannelHandler, testCases []ChannelSendTestCase, setupBackend func(*test.MockBackend)) { +func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler courier.ChannelHandler, testCases []ChannelSendTestCase, checkRedacted []string, setupBackend func(*test.MockBackend)) { mb := test.NewMockBackend() if setupBackend != nil { setupBackend(mb) @@ -241,7 +241,7 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour tc.SendPrep(server, handler, channel, msg) } - clog := courier.NewChannelLogForSend(msg, nil) + clog := courier.NewChannelLogForSend(msg, handler.RedactValues(channel)) ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*10) status, err := handler.Send(ctx, msg, clog) @@ -329,6 +329,8 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour require.Equal(urns.URN(tc.MsgURN), old) require.Equal(urns.URN(tc.ExpectedNewURN), new) } + + assertChannelLogRedaction(t, clog, checkRedacted) }) } @@ -456,3 +458,21 @@ func RunChannelBenchmarks(b *testing.B, channels []courier.Channel, handler cour }) } } + +// asserts that the given channel log doesn't contain any of the given values +func assertChannelLogRedaction(t *testing.T, clog *courier.ChannelLog, vals []string) { + assertRedacted := func(s string) { + for _, v := range vals { + assert.NotContains(t, s, v, "expected '%s' to not contain redacted value '%s'", s, v) + } + } + + for _, h := range clog.HTTPLogs() { + assertRedacted(h.URL) + assertRedacted(h.Request) + assertRedacted(h.Response) + } + for _, e := range clog.Errors() { + assertRedacted(e.Message()) + } +} diff --git a/handlers/thinq/thinq.go b/handlers/thinq/thinq.go index 99f0a7a90..50735b8cf 100644 --- a/handlers/thinq/thinq.go +++ b/handlers/thinq/thinq.go @@ -224,3 +224,9 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } + +func (h *handler) RedactValues(ch courier.Channel) []string { + return []string{ + handlers.BasicAuth(ch.StringConfigForKey(configAPITokenUser, ""), ch.StringConfigForKey(configAPIToken, "")), + } +} diff --git a/handlers/thinq/thinq_test.go b/handlers/thinq/thinq_test.go index 4597abfb3..03465fc48 100644 --- a/handlers/thinq/thinq_test.go +++ b/handlers/thinq/thinq_test.go @@ -160,5 +160,5 @@ func TestSending(t *testing.T) { configAPITokenUser: "user1", configAPIToken: "sesame", }) - RunChannelSendTestCases(t, channel, newHandler(), sendTestCases, nil) + RunChannelSendTestCases(t, channel, newHandler(), sendTestCases, []string{BasicAuth("user1", "sesame")}, nil) } diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index df39417cb..7f05b035c 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -18,13 +18,12 @@ import ( "strings" "github.com/buger/jsonparser" - "github.com/sirupsen/logrus" - "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) const ( @@ -308,6 +307,12 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } +func (h *handler) RedactValues(ch courier.Channel) []string { + return []string{ + handlers.BasicAuth(ch.StringConfigForKey(configAccountSID, ""), ch.StringConfigForKey(courier.ConfigAuthToken, "")), + } +} + func (h *handler) parseURN(channel courier.Channel, text, country string) (urns.URN, error) { if channel.IsScheme(urns.WhatsAppScheme) { // Twilio Whatsapp from is in the form: whatsapp:+12211414154 or +12211414154 diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index 2572da19c..bf6da4f4f 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -687,10 +687,10 @@ func TestSending(t *testing.T) { configSendURL: "BASE_URL", }) - RunChannelSendTestCases(t, defaultChannel, newTWIMLHandler("T", "Twilio", true), defaultSendTestCases, nil) - RunChannelSendTestCases(t, tmsDefaultChannel, newTWIMLHandler("TMS", "Twilio Messaging Service", true), tmsDefaultSendTestCases, nil) - RunChannelSendTestCases(t, twDefaultChannel, newTWIMLHandler("TW", "TwiML", true), twDefaultSendTestCases, nil) - RunChannelSendTestCases(t, swChannel, newTWIMLHandler("SW", "SignalWire", false), swSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newTWIMLHandler("T", "Twilio", true), defaultSendTestCases, []string{BasicAuth("accountSID", "authToken")}, nil) + RunChannelSendTestCases(t, tmsDefaultChannel, newTWIMLHandler("TMS", "Twilio Messaging Service", true), tmsDefaultSendTestCases, []string{BasicAuth("accountSID", "authToken")}, nil) + RunChannelSendTestCases(t, twDefaultChannel, newTWIMLHandler("TW", "TwiML", true), twDefaultSendTestCases, []string{BasicAuth("accountSID", "authToken")}, nil) + RunChannelSendTestCases(t, swChannel, newTWIMLHandler("SW", "SignalWire", false), swSendTestCases, []string{BasicAuth("accountSID", "authToken")}, nil) waChannel := test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SW", "+12065551212", "US", map[string]interface{}{ @@ -700,7 +700,7 @@ func TestSending(t *testing.T) { ) waChannel.SetScheme(urns.WhatsAppScheme) - RunChannelSendTestCases(t, waChannel, newTWIMLHandler("T", "Twilio Whatsapp", true), waSendTestCases, nil) + RunChannelSendTestCases(t, waChannel, newTWIMLHandler("T", "Twilio Whatsapp", true), waSendTestCases, []string{BasicAuth("accountSID", "authToken")}, nil) twaChannel := test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TWA", "+12065551212", "US", map[string]interface{}{ @@ -710,5 +710,5 @@ func TestSending(t *testing.T) { ) twaChannel.SetScheme(urns.WhatsAppScheme) - RunChannelSendTestCases(t, twaChannel, newTWIMLHandler("TWA", "Twilio Whatsapp", true), twaSendTestCases, nil) + RunChannelSendTestCases(t, twaChannel, newTWIMLHandler("TWA", "Twilio Whatsapp", true), twaSendTestCases, []string{BasicAuth("accountSID", "authToken")}, nil) } diff --git a/handlers/twitter/twitter_test.go b/handlers/twitter/twitter_test.go index 39119b7ab..b6a703b79 100644 --- a/handlers/twitter/twitter_test.go +++ b/handlers/twitter/twitter_test.go @@ -394,5 +394,5 @@ func TestSending(t *testing.T) { })) attachmentMockedSendTestCase := mockAttachmentURLs(mediaServer, defaultSendTestCases) - RunChannelSendTestCases(t, testChannels[0], newHandler("TWT", "Twitter Activity"), attachmentMockedSendTestCase, nil) + RunChannelSendTestCases(t, testChannels[0], newHandler("TWT", "Twitter Activity"), attachmentMockedSendTestCase, []string{"apiSecret", "accessTokenSecret"}, nil) } diff --git a/handlers/utils.go b/handlers/utils.go index a4fcc0381..28aa1029b 100644 --- a/handlers/utils.go +++ b/handlers/utils.go @@ -52,10 +52,10 @@ var base64Regex, _ = regexp.Compile("^([a-zA-Z0-9+/=]{4})+$") var base64Encoding = base64.StdEncoding.Strict() // DecodePossibleBase64 detects and decodes a possibly base64 encoded messages by doing: -// * check it's at least 60 characters -// * check its length is divisible by 4 -// * check that there's no whitespace -// * check the decoded string contains at least 50% ascii +// - check it's at least 60 characters +// - check its length is divisible by 4 +// - check that there's no whitespace +// - check the decoded string contains at least 50% ascii func DecodePossibleBase64(original string) string { stripped := strings.TrimSpace(strings.Replace(strings.Replace(original, "\r", "", -1), "\n", "", -1)) length := len([]rune(stripped)) @@ -143,3 +143,7 @@ func StrictTelForCountry(number string, country string) (urns.URN, error) { return urn, nil } + +func BasicAuth(user, pass string) string { + return base64.StdEncoding.EncodeToString([]byte(user + ":" + pass)) +} diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index 8e371e5e0..af6ec39d3 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -213,9 +213,9 @@ func TestSending(t *testing.T) { courier.ConfigAuthToken: "Token", "button_layout": map[string]interface{}{"bg_color": "#f7bb3f", "text": "*

", "text_size": "large"}, }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) - RunChannelSendTestCases(t, invalidTokenChannel, newHandler(), invalidTokenSendTestCases, nil) - RunChannelSendTestCases(t, buttonLayoutChannel, newHandler(), buttonLayoutSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"Token"}, nil) + RunChannelSendTestCases(t, invalidTokenChannel, newHandler(), invalidTokenSendTestCases, []string{"Token"}, nil) + RunChannelSendTestCases(t, buttonLayoutChannel, newHandler(), buttonLayoutSendTestCases, []string{"Token"}, nil) } var testChannels = []courier.Channel{ diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index 5533082c1..077ce3eec 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -502,5 +502,5 @@ func TestSend(t *testing.T) { res.Write([]byte("media body")) })) mockedSendTestCases := mockAttachmentURLs(mediaServer, sendTestCases) - RunChannelSendTestCases(t, testChannels[0], newHandler(), mockedSendTestCases, nil) + RunChannelSendTestCases(t, testChannels[0], newHandler(), mockedSendTestCases, []string{"token123xyz", "abc123xyz"}, nil) } diff --git a/handlers/wavy/wavy_test.go b/handlers/wavy/wavy_test.go index dc7d2734e..1e1768f4f 100644 --- a/handlers/wavy/wavy_test.go +++ b/handlers/wavy/wavy_test.go @@ -212,5 +212,5 @@ func TestSending(t *testing.T) { courier.ConfigUsername: "user1", courier.ConfigAuthToken: "token", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"token"}, nil) } diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index b4f6b184f..d912ade46 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -399,5 +399,5 @@ func setupBackend(mb *test.MockBackend) { func TestSending(t *testing.T) { maxMsgLength = 160 var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WC", "2020", "US", map[string]interface{}{configAppSecret: "secret", configAppID: "app-id"}) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, setupBackend) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"secret"}, setupBackend) } diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index 1c0ba87ec..196aba6ca 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -935,10 +935,10 @@ func TestSending(t *testing.T) { "version": "v2.35.2", }) - RunChannelSendTestCases(t, defaultChannel, newWAHandler(courier.ChannelType("WA"), "WhatsApp"), defaultSendTestCases, nil) - RunChannelSendTestCases(t, hsmSupportChannel, newWAHandler(courier.ChannelType("WA"), "WhatsApp"), hsmSupportSendTestCases, nil) - RunChannelSendTestCases(t, d3Channel, newWAHandler(courier.ChannelType("D3"), "360Dialog"), defaultSendTestCases, nil) - RunChannelSendTestCases(t, txwChannel, newWAHandler(courier.ChannelType("TXW"), "TextIt"), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newWAHandler(courier.ChannelType("WA"), "WhatsApp"), defaultSendTestCases, []string{"token123"}, nil) + RunChannelSendTestCases(t, hsmSupportChannel, newWAHandler(courier.ChannelType("WA"), "WhatsApp"), hsmSupportSendTestCases, []string{"token123"}, nil) + RunChannelSendTestCases(t, d3Channel, newWAHandler(courier.ChannelType("D3"), "360Dialog"), defaultSendTestCases, []string{"token123"}, nil) + RunChannelSendTestCases(t, txwChannel, newWAHandler(courier.ChannelType("TXW"), "TextIt"), defaultSendTestCases, []string{"token123"}, nil) mediaServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { defer req.Body.Close() @@ -948,5 +948,5 @@ func TestSending(t *testing.T) { defer mediaServer.Close() mediaCacheSendTestCases := mockAttachmentURLs(mediaServer, mediaCacheSendTestCases) - RunChannelSendTestCases(t, defaultChannel, newWAHandler(courier.ChannelType("WA"), "WhatsApp"), mediaCacheSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newWAHandler(courier.ChannelType("WA"), "WhatsApp"), mediaCacheSendTestCases, []string{"token123"}, nil) } diff --git a/handlers/yo/yo_test.go b/handlers/yo/yo_test.go index ed27d7d71..fb6d14c0a 100644 --- a/handlers/yo/yo_test.go +++ b/handlers/yo/yo_test.go @@ -101,5 +101,5 @@ var getSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { var getChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "YO", "2020", "US", map[string]interface{}{"username": "yo-username", "password": "yo-password"}) - RunChannelSendTestCases(t, getChannel, newHandler(), getSendTestCases, nil) + RunChannelSendTestCases(t, getChannel, newHandler(), getSendTestCases, []string{"yo-password"}, nil) } diff --git a/handlers/zenvia/zenvia_test.go b/handlers/zenvia/zenvia_test.go index a052d7f5d..3128fcd77 100644 --- a/handlers/zenvia/zenvia_test.go +++ b/handlers/zenvia/zenvia_test.go @@ -410,8 +410,8 @@ var defaultSMSSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 var defaultWhatsappChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZVW", "2020", "BR", map[string]interface{}{"api_key": "zv-api-token"}) - RunChannelSendTestCases(t, defaultWhatsappChannel, newHandler("ZVW", "Zenvia WhatsApp"), defaultWhatsappSendTestCases, nil) + RunChannelSendTestCases(t, defaultWhatsappChannel, newHandler("ZVW", "Zenvia WhatsApp"), defaultWhatsappSendTestCases, []string{"zv-api-token"}, nil) var defaultSMSChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZVS", "2020", "BR", map[string]interface{}{"api_key": "zv-api-token"}) - RunChannelSendTestCases(t, defaultSMSChannel, newHandler("ZVS", "Zenvia SMS"), defaultSMSSendTestCases, nil) + RunChannelSendTestCases(t, defaultSMSChannel, newHandler("ZVS", "Zenvia SMS"), defaultSMSSendTestCases, []string{"zv-api-token"}, nil) } diff --git a/handlers/zenviaold/zenviaold.go b/handlers/zenviaold/zenviaold.go index afeec2f8c..7ce1fbb8c 100644 --- a/handlers/zenviaold/zenviaold.go +++ b/handlers/zenviaold/zenviaold.go @@ -211,5 +211,10 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann status.SetStatus(courier.MsgWired) } return status, nil +} +func (h *handler) RedactValues(ch courier.Channel) []string { + return []string{ + handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + } } diff --git a/handlers/zenviaold/zenviaold_test.go b/handlers/zenviaold/zenviaold_test.go index 1a0087299..26526cb94 100644 --- a/handlers/zenviaold/zenviaold_test.go +++ b/handlers/zenviaold/zenviaold_test.go @@ -216,5 +216,5 @@ func TestSending(t *testing.T) { maxMsgLength = 160 var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZV", "2020", "BR", map[string]interface{}{"username": "zv-username", "password": "zv-password"}) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{BasicAuth("zv-username", "zv-password")}, nil) } diff --git a/sender.go b/sender.go index e6aa10fa0..d2c46939f 100644 --- a/sender.go +++ b/sender.go @@ -157,6 +157,13 @@ func (w *Sender) sendMessage(msg Msg) { server := w.foreman.server backend := server.Backend() + // find the handler for this channel type + handler := server.GetHandler(msg.Channel()) + if handler == nil { + log.Errorf("unable to find handler for channel type: %s", msg.Channel().ChannelType()) + return + } + // we don't want any individual send taking more than 35s sendCTX, cancel := context.WithTimeout(context.Background(), time.Second*35) defer cancel() @@ -177,7 +184,6 @@ func (w *Sender) sendMessage(msg Msg) { if err != nil { log.WithError(err).Error("error clearing sent status for msg") } - } // was this msg already sent? (from a double queue?) @@ -189,7 +195,7 @@ func (w *Sender) sendMessage(msg Msg) { } var status MsgStatus - clog := NewChannelLogForSend(msg, nil) // TODO get redact values from handler + clog := NewChannelLogForSend(msg, handler.RedactValues(msg.Channel())) if sent { // if this message was already sent, create a wired status for it @@ -197,7 +203,7 @@ func (w *Sender) sendMessage(msg Msg) { log.Warning("duplicate send, marking as wired") } else { // send our message - status, err = server.SendMsg(sendCTX, msg, clog) + status, err = handler.Send(sendCTX, msg, clog) duration := time.Since(start) secondDuration := float64(duration) / float64(time.Second) diff --git a/server.go b/server.go index 475eccbfc..e82945422 100644 --- a/server.go +++ b/server.go @@ -29,8 +29,7 @@ type Server interface { Config() *Config AddHandlerRoute(handler ChannelHandler, method string, action string, handlerFunc ChannelHandleFunc) - - SendMsg(context.Context, Msg, *ChannelLog) (MsgStatus, error) + GetHandler(Channel) ChannelHandler Backend() Backend @@ -203,16 +202,7 @@ func (s *server) Stop() error { return nil } -func (s *server) SendMsg(ctx context.Context, msg Msg, clog *ChannelLog) (MsgStatus, error) { - // find the handler for this message type - handler, found := activeHandlers[msg.Channel().ChannelType()] - if !found { - return nil, fmt.Errorf("unable to find handler for channel type: %s", msg.Channel().ChannelType()) - } - - // have the handler send it - return handler.Send(ctx, msg, clog) -} +func (s *server) GetHandler(ch Channel) ChannelHandler { return activeHandlers[ch.ChannelType()] } func (s *server) WaitGroup() *sync.WaitGroup { return s.waitGroup } func (s *server) StopChan() chan bool { return s.stopChan } From c49f406f144835d522def9bfaad992999dc2aafd Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 8 Sep 2022 16:21:25 -0500 Subject: [PATCH 149/294] Fix failing messages if we don't have a registered handler --- handler_test.go | 4 ++-- sender.go | 25 +++++++++++++++---------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/handler_test.go b/handler_test.go index 1bd62869c..1a8f7ea6a 100644 --- a/handler_test.go +++ b/handler_test.go @@ -98,10 +98,10 @@ func TestHandling(t *testing.T) { // sleep a second, sender should take care of it in that time time.Sleep(time.Second) - // message should have errored because we don't have a registered handler + // message should have failed because we don't have a registered handler assert.Equal(1, len(mb.WrittenMsgStatuses())) assert.Equal(msg.ID(), mb.WrittenMsgStatuses()[0].ID()) - assert.Equal(courier.MsgErrored, mb.WrittenMsgStatuses()[0].Status()) + assert.Equal(courier.MsgFailed, mb.WrittenMsgStatuses()[0].Status()) assert.Equal(1, len(mb.WrittenChannelLogs())) mb.Reset() diff --git a/sender.go b/sender.go index d2c46939f..0ad8a2298 100644 --- a/sender.go +++ b/sender.go @@ -157,13 +157,6 @@ func (w *Sender) sendMessage(msg Msg) { server := w.foreman.server backend := server.Backend() - // find the handler for this channel type - handler := server.GetHandler(msg.Channel()) - if handler == nil { - log.Errorf("unable to find handler for channel type: %s", msg.Channel().ChannelType()) - return - } - // we don't want any individual send taking more than 35s sendCTX, cancel := context.WithTimeout(context.Background(), time.Second*35) defer cancel() @@ -195,12 +188,24 @@ func (w *Sender) sendMessage(msg Msg) { } var status MsgStatus - clog := NewChannelLogForSend(msg, handler.RedactValues(msg.Channel())) + var redactValues []string + handler := server.GetHandler(msg.Channel()) + if handler != nil { + handler.RedactValues(msg.Channel()) + } + + clog := NewChannelLogForSend(msg, redactValues) + + if handler == nil { + // if there's no handler, create a FAILED status for it + status = backend.NewMsgStatusForID(msg.Channel(), msg.ID(), MsgFailed, clog) + log.Errorf("unable to find handler for channel type: %s", msg.Channel().ChannelType()) - if sent { - // if this message was already sent, create a wired status for it + } else if sent { + // if this message was already sent, create a WIRED status for it status = backend.NewMsgStatusForID(msg.Channel(), msg.ID(), MsgWired, clog) log.Warning("duplicate send, marking as wired") + } else { // send our message status, err = handler.Send(sendCTX, msg, clog) From 9a524a07087133d517d3106f2c07ae96f8d8c666 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 9 Sep 2022 10:47:17 -0500 Subject: [PATCH 150/294] Add tests for redaction in DescribeURN calls --- handlers/facebook/facebook_test.go | 10 ++++--- handlers/facebookapp/facebookapp_test.go | 33 +++++++++++++++--------- handlers/jiochat/jiochat_test.go | 4 ++- handlers/slack/slack_test.go | 8 +++--- handlers/test.go | 4 +-- handlers/vk/vk_test.go | 8 +++--- handlers/wechat/wechat_test.go | 6 +++-- 7 files changed, 46 insertions(+), 27 deletions(-) diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index 33d3bda65..54d051e43 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -633,13 +633,13 @@ func buildMockFBGraph(testCases []ChannelHandleTestCase) *httptest.Server { return server } -func TestDescribe(t *testing.T) { +func TestDescribeURN(t *testing.T) { fbGraph := buildMockFBGraph(testCases) defer fbGraph.Close() channel := testChannels[0] - handler := newHandler().(courier.URNDescriber) - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, nil) + handler := newHandler() + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, handler.RedactValues(channel)) tcs := []struct { urn urns.URN @@ -651,9 +651,11 @@ func TestDescribe(t *testing.T) { } for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), channel, tc.urn, clog) + metadata, _ := handler.(courier.URNDescriber).DescribeURN(context.Background(), channel, tc.urn, clog) assert.Equal(t, metadata, tc.expectedMetadata) } + + AssertChannelLogRedaction(t, clog, []string{"a123", "mysecret"}) } func TestHandler(t *testing.T) { diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 6562cbe55..e4aa54795 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -464,13 +464,14 @@ func buildMockFBGraphIG(testCases []ChannelHandleTestCase) *httptest.Server { return server } -func TestDescribeFBA(t *testing.T) { +func TestDescribeURNForFBA(t *testing.T) { fbGraph := buildMockFBGraphFBA(testCasesFBA) defer fbGraph.Close() channel := testChannelsFBA[0] - handler := newHandler("FBA", "Facebook", false).(courier.URNDescriber) - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, nil) + handler := newHandler("FBA", "Facebook", false) + handler.Initialize(newServer(nil)) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, handler.RedactValues(channel)) tcs := []struct { urn urns.URN @@ -482,18 +483,21 @@ func TestDescribeFBA(t *testing.T) { } for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), channel, tc.urn, clog) + metadata, _ := handler.(courier.URNDescriber).DescribeURN(context.Background(), channel, tc.urn, clog) assert.Equal(t, metadata, tc.expectedMetadata) } + + AssertChannelLogRedaction(t, clog, []string{"a123", "wac_admin_system_user_token"}) } -func TestDescribeIG(t *testing.T) { +func TestDescribeURNForIG(t *testing.T) { fbGraph := buildMockFBGraphIG(testCasesIG) defer fbGraph.Close() channel := testChannelsIG[0] - handler := newHandler("IG", "Instagram", false).(courier.URNDescriber) - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, nil) + handler := newHandler("IG", "Instagram", false) + handler.Initialize(newServer(nil)) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, handler.RedactValues(channel)) tcs := []struct { urn urns.URN @@ -504,15 +508,18 @@ func TestDescribeIG(t *testing.T) { } for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), channel, tc.urn, clog) + metadata, _ := handler.(courier.URNDescriber).DescribeURN(context.Background(), channel, tc.urn, clog) assert.Equal(t, metadata, tc.expectedMetadata) } + + AssertChannelLogRedaction(t, clog, []string{"a123", "wac_admin_system_user_token"}) } -func TestDescribeWAC(t *testing.T) { +func TestDescribeURNForWAC(t *testing.T) { channel := testChannelsWAC[0] - handler := newHandler("WAC", "Cloud API WhatsApp", false).(courier.URNDescriber) - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, nil) + handler := newHandler("WAC", "Cloud API WhatsApp", false) + handler.Initialize(newServer(nil)) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, handler.RedactValues(channel)) tcs := []struct { urn urns.URN @@ -523,9 +530,11 @@ func TestDescribeWAC(t *testing.T) { } for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), testChannelsWAC[0], tc.urn, clog) + metadata, _ := handler.(courier.URNDescriber).DescribeURN(context.Background(), testChannelsWAC[0], tc.urn, clog) assert.Equal(t, metadata, tc.expectedMetadata) } + + AssertChannelLogRedaction(t, clog, []string{"a123", "wac_admin_system_user_token"}) } var wacReceiveURL = "/c/wac/receive" diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index 18e8fa9c1..266a697a3 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -285,7 +285,7 @@ func TestDescribeURN(t *testing.T) { s := newServer(mb) handler := &handler{handlers.NewBaseHandler(courier.ChannelType("JC"), "Jiochat")} handler.Initialize(s) - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], nil) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], handler.RedactValues(testChannels[0])) tcs := []struct { urn urns.URN @@ -299,6 +299,8 @@ func TestDescribeURN(t *testing.T) { metadata, _ := handler.DescribeURN(context.Background(), testChannels[0], tc.urn, clog) assert.Equal(t, metadata, tc.expectedMetadata) } + + AssertChannelLogRedaction(t, clog, []string{"secret"}) } func TestBuildMediaRequest(t *testing.T) { diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index d2ac5719d..96e633414 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -359,13 +359,15 @@ func TestDescribeURN(t *testing.T) { server := buildMockSlackService([]ChannelHandleTestCase{}) defer server.Close() - handler := newHandler().(courier.URNDescriber) - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], nil) + handler := newHandler() + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], handler.RedactValues(testChannels[0])) urn, _ := urns.NewURNFromParts(urns.SlackScheme, "U012345", "", "") data := map[string]string{"name": "dummy user"} - describe, err := handler.DescribeURN(context.Background(), testChannels[0], urn, clog) + describe, err := handler.(courier.URNDescriber).DescribeURN(context.Background(), testChannels[0], urn, clog) assert.Nil(t, err) assert.Equal(t, data, describe) + + AssertChannelLogRedaction(t, clog, []string{"xoxb-abc123", "one-long-verification-token"}) } diff --git a/handlers/test.go b/handlers/test.go index 2b835c4ef..e2c5c67f7 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -330,7 +330,7 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour require.Equal(urns.URN(tc.ExpectedNewURN), new) } - assertChannelLogRedaction(t, clog, checkRedacted) + AssertChannelLogRedaction(t, clog, checkRedacted) }) } @@ -460,7 +460,7 @@ func RunChannelBenchmarks(b *testing.B, channels []courier.Channel, handler cour } // asserts that the given channel log doesn't contain any of the given values -func assertChannelLogRedaction(t *testing.T, clog *courier.ChannelLog, vals []string) { +func AssertChannelLogRedaction(t *testing.T, clog *courier.ChannelLog, vals []string) { assertRedacted := func(s string) { for _, v := range vals { assert.NotContains(t, s, v, "expected '%s' to not contain redacted value '%s'", s, v) diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index 077ce3eec..85911f40e 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -375,14 +375,16 @@ func TestDescribeURN(t *testing.T) { server := buildMockVKService([]ChannelHandleTestCase{}) defer server.Close() - handler := newHandler().(courier.URNDescriber) - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], nil) + handler := newHandler() + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], handler.RedactValues(testChannels[0])) urn, _ := urns.NewURNFromParts(urns.VKScheme, "123456789", "", "") data := map[string]string{"name": "John Doe"} - describe, err := handler.DescribeURN(context.Background(), testChannels[0], urn, clog) + describe, err := handler.(courier.URNDescriber).DescribeURN(context.Background(), testChannels[0], urn, clog) assert.Nil(t, err) assert.Equal(t, data, describe) + + AssertChannelLogRedaction(t, clog, []string{"token123xyz", "abc123xyz"}) } // setSendURL takes care of setting the send_url to our test server host diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index d912ade46..ac34f2ed4 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -264,7 +264,7 @@ func newServer(backend courier.Backend) courier.Server { return courier.NewServerWithLogger(config, backend, logger) } -func TestDescribe(t *testing.T) { +func TestDescribeURN(t *testing.T) { WCAPI := buildMockWCAPI(testCases) defer WCAPI.Close() @@ -281,7 +281,7 @@ func TestDescribe(t *testing.T) { s := newServer(mb) handler := &handler{NewBaseHandler(courier.ChannelType("WC"), "WeChat")} handler.Initialize(s) - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], nil) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], handler.RedactValues(testChannels[0])) tcs := []struct { urn urns.URN @@ -295,6 +295,8 @@ func TestDescribe(t *testing.T) { metadata, _ := handler.DescribeURN(context.Background(), testChannels[0], tc.urn, clog) assert.Equal(t, metadata, tc.expectedMetadata) } + + AssertChannelLogRedaction(t, clog, []string{"secret"}) } func TestBuildMediaRequest(t *testing.T) { From 1abaea62408d0db0d537eedf7acd8ea2ad9c5de8 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 9 Sep 2022 12:10:38 -0500 Subject: [PATCH 151/294] Update to latest gocommon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ee0a51f73..c46a3aa6c 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.6 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.29.0 + github.com/nyaruka/gocommon v1.30.0 github.com/nyaruka/null v1.2.0 github.com/nyaruka/redisx v0.2.2 github.com/patrickmn/go-cache v2.1.0+incompatible diff --git a/go.sum b/go.sum index 401415384..24e02beae 100644 --- a/go.sum +++ b/go.sum @@ -76,8 +76,8 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.29.0 h1:BNhlqYiA0KceBgRmjWIOMSFsiEwtopkGGQ4W38wD56o= -github.com/nyaruka/gocommon v1.29.0/go.mod h1:g6/d9drZXDUrtRSPe2Kf8lTUS+baHt/0G0dwHq3qeIU= +github.com/nyaruka/gocommon v1.30.0 h1:394CU1fxGXSs+mrd5x8nXnqw2epT9P0ui/9MtSE2ycQ= +github.com/nyaruka/gocommon v1.30.0/go.mod h1:PApT/06fP5Tzs4/kbkJ+rVoyOc9Lbqm1lR0ow8Vqzp0= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= From ad57025e9b1e5092572bde0afc6bf0914a694fb3 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 9 Sep 2022 12:22:32 -0500 Subject: [PATCH 152/294] Fix linter warnings --- backends/rapidpro/backend_test.go | 4 ++++ backends/rapidpro/channel.go | 10 --------- cmd/fuzzer/main.go | 2 +- handlers/discord/discord.go | 7 +------ handlers/external/external.go | 5 +---- handlers/facebook/facebook_test.go | 4 ++-- handlers/responses.go | 2 +- handlers/wavy/wavy.go | 3 +-- handlers/yo/yo.go | 4 ++-- handlers/zenvia/zenvia_test.go | 33 ------------------------------ msg.go | 2 +- queue/queue.go | 6 +++--- queue/queue_test.go | 4 ++-- 13 files changed, 19 insertions(+), 67 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 7716cf42a..1e4dba17c 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -376,12 +376,14 @@ func (ts *BackendTestSuite) TestContactURN() { contact, err := contactForURN(ctx, ts.b, knChannel.OrgID_, knChannel, urn, "", "", clog) ts.NoError(err) + ts.NotNil(contact) tx, err := ts.b.db.Beginx() ts.NoError(err) contact, err = contactForURN(ctx, ts.b, twChannel.OrgID_, twChannel, urn, "chestnut", "", clog) ts.NoError(err) + ts.NotNil(contact) contactURNs, err := contactURNsForContact(tx, contact.ID_) ts.NoError(err) @@ -433,6 +435,7 @@ func (ts *BackendTestSuite) TestContactURN() { tgURNDisplay, _ := urns.NewTelegramURN(12345, "Jane") displayContact, err := contactForURN(ctx, ts.b, tgChannel.OrgID_, tgChannel, tgURNDisplay, "", "", clog) + ts.NoError(err) ts.Equal(tgContact.URNID_, displayContact.URNID_) ts.Equal(tgContact.ID_, displayContact.ID_) @@ -1155,6 +1158,7 @@ func (ts *BackendTestSuite) TestWriteMsg() { ts.NotNil(m.QueuedOn_) contact, err := contactForURN(ctx, ts.b, m.OrgID_, knChannel, urn, "", "", clog) + ts.NoError(err) ts.Equal(null.String("test contact"), contact.Name_) ts.Equal(m.OrgID_, contact.OrgID_) ts.Equal(m.ContactID_, contact.ID_) diff --git a/backends/rapidpro/channel.go b/backends/rapidpro/channel.go index 565178670..504a85479 100644 --- a/backends/rapidpro/channel.go +++ b/backends/rapidpro/channel.go @@ -409,13 +409,3 @@ func (c *DBChannel) IntConfigForKey(key string, defaultValue int) int { func (c *DBChannel) CallbackDomain(fallbackDomain string) string { return c.StringConfigForKey(courier.ConfigCallbackDomain, fallbackDomain) } - -// supportsScheme returns whether the passed in channel supports the passed in scheme -func (c *DBChannel) supportsScheme(scheme string) bool { - for _, s := range c.Schemes_ { - if s == scheme { - return true - } - } - return false -} diff --git a/cmd/fuzzer/main.go b/cmd/fuzzer/main.go index ac99250ad..b4abbe325 100644 --- a/cmd/fuzzer/main.go +++ b/cmd/fuzzer/main.go @@ -27,7 +27,7 @@ func main() { MaxIdle: 2, // only keep up to 2 idle IdleTimeout: 240 * time.Second, // how long to wait before reaping a connection Dial: func() (redis.Conn, error) { - conn, err := redis.Dial("tcp", fmt.Sprintf("%s", redisURL.Host)) + conn, err := redis.Dial("tcp", redisURL.Host) if err != nil { return nil, err } diff --git a/handlers/discord/discord.go b/handlers/discord/discord.go index d7f2b2d36..354231b15 100644 --- a/handlers/discord/discord.go +++ b/handlers/discord/discord.go @@ -52,10 +52,6 @@ func (h *handler) Initialize(s courier.Server) error { return nil } -type stopContactForm struct { - From string `validate:"required" name:"from"` -} - // utility function to grab the form value for either the passed in name (if non-empty) or the first set // value from defaultNames func getFormField(form url.Values, name string) string { @@ -95,8 +91,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w date := time.Now() // create our URN - urn := urns.NilURN - urn, err = urns.NewURNFromParts(urns.DiscordScheme, from, "", "") + urn, err := urns.NewURNFromParts(urns.DiscordScheme, from, "", "") if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } diff --git a/handlers/external/external.go b/handlers/external/external.go index fdaf94537..f2f3cc220 100644 --- a/handlers/external/external.go +++ b/handlers/external/external.go @@ -12,12 +12,11 @@ import ( "strings" "time" + "github.com/antchfx/xmlquery" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/gocommon/gsm7" "github.com/nyaruka/gocommon/urns" - - "github.com/antchfx/xmlquery" "github.com/pkg/errors" ) @@ -437,5 +436,3 @@ func replaceVariables(text string, variables map[string]string) string { } return text } - -const defaultSendBody = `id={{id}}&text={{text}}&to={{to}}&to_no_plus={{to_no_plus}}&from={{from}}&from_no_plus={{from_no_plus}}&channel={{channel}}` diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index d1d01cc73..06ee0e1d3 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -616,7 +616,7 @@ func buildMockFBGraph(testCases []ChannelHandleTestCase) *httptest.Server { // invalid auth token if accessToken != "a123" { - http.Error(w, "invalid auth token", 403) + http.Error(w, "invalid auth token", http.StatusForbidden) } // user has a name @@ -676,7 +676,7 @@ func TestVerify(t *testing.T) { // invalid auth token if accessToken != "a123" { fmt.Printf("Access token: %s\n", accessToken) - http.Error(w, "invalid auth token", 403) + http.Error(w, "invalid auth token", http.StatusForbidden) return } diff --git a/handlers/responses.go b/handlers/responses.go index 119fa60cb..7cd84d737 100644 --- a/handlers/responses.go +++ b/handlers/responses.go @@ -18,7 +18,7 @@ type ResponseWriter interface { // WriteMsgsAndResponse writes the passed in message to our backend func WriteMsgsAndResponse(ctx context.Context, h ResponseWriter, msgs []courier.Msg, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { - events := make([]courier.Event, len(msgs), len(msgs)) + events := make([]courier.Event, len(msgs)) for i, m := range msgs { err := h.Backend().WriteMsg(ctx, m, clog) if err != nil { diff --git a/handlers/wavy/wavy.go b/handlers/wavy/wavy.go index 2c061e413..d2814ae85 100644 --- a/handlers/wavy/wavy.go +++ b/handlers/wavy/wavy.go @@ -15,8 +15,7 @@ import ( ) var ( - sendURL = "https://api-messaging.movile.com/v1/send-sms" - maxMsgLength = 160 + sendURL = "https://api-messaging.movile.com/v1/send-sms" ) type handler struct { diff --git a/handlers/yo/yo.go b/handlers/yo/yo.go index 502bba98f..5a57f6fbf 100644 --- a/handlers/yo/yo.go +++ b/handlers/yo/yo.go @@ -138,7 +138,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann responseQS, _ := url.ParseQuery(string(respBody)) // check whether we were blacklisted - createMessage, _ := responseQS["ybs_autocreate_message"] + createMessage := responseQS["ybs_autocreate_message"] if len(createMessage) > 0 && strings.Contains(createMessage[0], "BLACKLISTED") { status.SetStatus(courier.MsgFailed) @@ -153,7 +153,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } // finally check that we were sent - createStatus, _ := responseQS["ybs_autocreate_status"] + createStatus := responseQS["ybs_autocreate_status"] if len(createStatus) > 0 && createStatus[0] == "OK" { status.SetStatus(courier.MsgWired) return status, nil diff --git a/handlers/zenvia/zenvia_test.go b/handlers/zenvia/zenvia_test.go index a052d7f5d..bc3271e2e 100644 --- a/handlers/zenvia/zenvia_test.go +++ b/handlers/zenvia/zenvia_test.go @@ -53,17 +53,6 @@ var unknownStatus = `{ } }` -var invalidTypeStatus = `{ - "id": "string", - "type": "MESSAGE_REPORT", - "channel": "string", - "messageId": "hs765939216", - "messageStatus": { - "timestamp": "2021-03-12T12:15:31Z", - "code": "SENT" - } -}` - var validReceive = `{ "id": "string", "timestamp": "2017-05-03T03:04:45Z", @@ -129,28 +118,6 @@ var locationReceive = `{ } }` -var invalidURN = `{ - "id": "string", - "timestamp": "2017-05-03T03:04:45Z", - "type": "MESSAGE", - "message": { - "id": "string", - "from": "MTN", - "to": "2020", - "direction": "IN", - "contents": [ - { - "type": "text", - "text": "Msg", - "payload": "string" - } - ], - "visitor": { - "name": "Bob" - } - } -}` - var invalidDateReceive = `{ "id": "string", "timestamp": "2014-08-26T12:55:48.593-03:00", diff --git a/msg.go b/msg.go index c94dd6491..b5b482cfd 100644 --- a/msg.go +++ b/msg.go @@ -17,7 +17,7 @@ import ( var ErrMsgNotFound = errors.New("message not found") // ErrWrongIncomingMsgStatus use do ignore the status update if the DB raise this -var ErrWrongIncomingMsgStatus = errors.New("Incoming messages can only be PENDING or HANDLED") +var ErrWrongIncomingMsgStatus = errors.New("incoming messages can only be PENDING or HANDLED") // MsgID is our typing of the db int type type MsgID null.Int diff --git a/queue/queue.go b/queue/queue.go index 02fc25930..2dd5b3123 100644 --- a/queue/queue.go +++ b/queue/queue.go @@ -259,13 +259,13 @@ var luaDethrottle = redis.NewScript(1, `-- KEYS: [QueueType] // StartDethrottler starts a goroutine responsible for dethrottling any queues that were // throttled every second. The passed in quitter chan can be used to shut down the goroutine func StartDethrottler(redis *redis.Pool, quitter chan bool, wg *sync.WaitGroup, qType string) { - go func() { - wg.Add(1) + wg.Add(1) + go func() { // figure out our next delay, we want to land just on the other side of a second boundary delay := time.Second - time.Duration(time.Now().UnixNano()%int64(time.Second)) - for true { + for { select { case <-quitter: wg.Done() diff --git a/queue/queue_test.go b/queue/queue_test.go index 7a0a69a61..5f6d11eeb 100644 --- a/queue/queue_test.go +++ b/queue/queue_test.go @@ -239,7 +239,7 @@ func TestLua(t *testing.T) { } -func nTestThrottle(t *testing.T) { +func TestThrottle(t *testing.T) { assert := assert.New(t) pool := getPool() conn := pool.Get() @@ -289,7 +289,7 @@ func nTestThrottle(t *testing.T) { // if this took less than 1 second or more than 3 seconds, fail, should have throttled expected := time.Duration((insertCount / rate) - 2) - elapsed := time.Now().Sub(start) + elapsed := time.Since(start) if elapsed < expected*time.Second || elapsed > (expected+2)*time.Second { t.Errorf("Did not throttle properly, took: %f", elapsed.Seconds()) } From fc6f427cb24d8cb651ba72804afc5ba06f3e298c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 9 Sep 2022 12:28:38 -0500 Subject: [PATCH 153/294] Use httpx.BasicAuth --- handlers/blackmyna/blackmyna.go | 3 ++- handlers/blackmyna/blackmyna_test.go | 3 ++- handlers/burstsms/burstsms.go | 3 ++- handlers/burstsms/burstsms_test.go | 3 ++- handlers/clicksend/clicksend.go | 3 ++- handlers/clicksend/clicksend_test.go | 3 ++- handlers/i2sms/i2sms.go | 3 ++- handlers/i2sms/i2sms_test.go | 3 ++- handlers/infobip/infobip.go | 3 ++- handlers/infobip/infobip_test.go | 5 +++-- handlers/junebug/junebug.go | 3 ++- handlers/junebug/junebug_test.go | 5 +++-- handlers/playmobile/playmobile.go | 3 ++- handlers/playmobile/playmobile_test.go | 3 ++- handlers/plivo/plivo.go | 3 ++- handlers/plivo/plivo_test.go | 3 ++- handlers/start/start.go | 3 ++- handlers/start/start_test.go | 3 ++- handlers/thinq/thinq.go | 3 ++- handlers/thinq/thinq_test.go | 3 ++- handlers/twiml/twiml.go | 3 ++- handlers/twiml/twiml_test.go | 13 +++++++------ handlers/utils.go | 4 ---- handlers/zenviaold/zenviaold.go | 3 ++- handlers/zenviaold/zenviaold_test.go | 3 ++- 25 files changed, 55 insertions(+), 35 deletions(-) diff --git a/handlers/blackmyna/blackmyna.go b/handlers/blackmyna/blackmyna.go index 69f1f37c0..1ae36a19c 100644 --- a/handlers/blackmyna/blackmyna.go +++ b/handlers/blackmyna/blackmyna.go @@ -10,6 +10,7 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/httpx" "github.com/pkg/errors" ) @@ -147,6 +148,6 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann func (h *handler) RedactValues(ch courier.Channel) []string { return []string{ - handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + httpx.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), } } diff --git a/handlers/blackmyna/blackmyna_test.go b/handlers/blackmyna/blackmyna_test.go index 58d281ec3..24360095b 100644 --- a/handlers/blackmyna/blackmyna_test.go +++ b/handlers/blackmyna/blackmyna_test.go @@ -7,6 +7,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) var testChannels = []courier.Channel{ @@ -146,5 +147,5 @@ func TestSending(t *testing.T) { courier.ConfigAPIKey: "KEY", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{BasicAuth("Username", "Password")}, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{httpx.BasicAuth("Username", "Password")}, nil) } diff --git a/handlers/burstsms/burstsms.go b/handlers/burstsms/burstsms.go index cd68021e3..e4a243935 100644 --- a/handlers/burstsms/burstsms.go +++ b/handlers/burstsms/burstsms.go @@ -10,6 +10,7 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/httpx" ) var ( @@ -111,6 +112,6 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann func (h *handler) RedactValues(ch courier.Channel) []string { return []string{ - handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + httpx.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), } } diff --git a/handlers/burstsms/burstsms_test.go b/handlers/burstsms/burstsms_test.go index c41bca01e..64f5f8a42 100644 --- a/handlers/burstsms/burstsms_test.go +++ b/handlers/burstsms/burstsms_test.go @@ -7,6 +7,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) var testChannels = []courier.Channel{ @@ -115,5 +116,5 @@ func TestSending(t *testing.T) { courier.ConfigUsername: "user1", courier.ConfigPassword: "pass1", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{BasicAuth("user1", "pass1")}, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{httpx.BasicAuth("user1", "pass1")}, nil) } diff --git a/handlers/clicksend/clicksend.go b/handlers/clicksend/clicksend.go index c38f1754b..69d0a649a 100644 --- a/handlers/clicksend/clicksend.go +++ b/handlers/clicksend/clicksend.go @@ -10,6 +10,7 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/httpx" "github.com/pkg/errors" ) @@ -121,6 +122,6 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann func (h *handler) RedactValues(ch courier.Channel) []string { return []string{ - handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + httpx.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), } } diff --git a/handlers/clicksend/clicksend_test.go b/handlers/clicksend/clicksend_test.go index 36f646e78..376cd2eed 100644 --- a/handlers/clicksend/clicksend_test.go +++ b/handlers/clicksend/clicksend_test.go @@ -7,6 +7,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) const ( @@ -174,5 +175,5 @@ func TestSending(t *testing.T) { }, ) - RunChannelSendTestCases(t, defaultChannel, newHandler(), sendTestCases, []string{BasicAuth("Aladdin", "open sesame")}, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), sendTestCases, []string{httpx.BasicAuth("Aladdin", "open sesame")}, nil) } diff --git a/handlers/i2sms/i2sms.go b/handlers/i2sms/i2sms.go index 702301543..fe8e80baf 100644 --- a/handlers/i2sms/i2sms.go +++ b/handlers/i2sms/i2sms.go @@ -11,6 +11,7 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/httpx" ) const ( @@ -145,7 +146,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann func (h *handler) RedactValues(ch courier.Channel) []string { return []string{ - handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + httpx.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), ch.StringConfigForKey(configChannelHash, ""), } } diff --git a/handlers/i2sms/i2sms_test.go b/handlers/i2sms/i2sms_test.go index 5d597d9d7..2bb5c1d57 100644 --- a/handlers/i2sms/i2sms_test.go +++ b/handlers/i2sms/i2sms_test.go @@ -7,6 +7,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) var testChannels = []courier.Channel{ @@ -104,5 +105,5 @@ func TestSending(t *testing.T) { courier.ConfigPassword: "pass1", configChannelHash: "hash123", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{BasicAuth("user1", "pass1"), "hash123"}, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{httpx.BasicAuth("user1", "pass1"), "hash123"}, nil) } diff --git a/handlers/infobip/infobip.go b/handlers/infobip/infobip.go index 385f78a7f..a1bc04880 100644 --- a/handlers/infobip/infobip.go +++ b/handlers/infobip/infobip.go @@ -12,6 +12,7 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/httpx" "github.com/pkg/errors" ) @@ -249,7 +250,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann func (h *handler) RedactValues(ch courier.Channel) []string { return []string{ - handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + httpx.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), } } diff --git a/handlers/infobip/infobip_test.go b/handlers/infobip/infobip_test.go index 3503628e0..c662eb3d5 100644 --- a/handlers/infobip/infobip_test.go +++ b/handlers/infobip/infobip_test.go @@ -8,6 +8,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) var testChannels = []courier.Channel{ @@ -408,7 +409,7 @@ func TestSending(t *testing.T) { courier.ConfigUsername: "Username", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{BasicAuth("Username", "Password")}, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{httpx.BasicAuth("Username", "Password")}, nil) var transChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "IB", "2020", "US", map[string]interface{}{ @@ -417,5 +418,5 @@ func TestSending(t *testing.T) { configTransliteration: "COLOMBIAN", }) - RunChannelSendTestCases(t, transChannel, newHandler(), transSendTestCases, []string{BasicAuth("Username", "Password")}, nil) + RunChannelSendTestCases(t, transChannel, newHandler(), transSendTestCases, []string{httpx.BasicAuth("Username", "Password")}, nil) } diff --git a/handlers/junebug/junebug.go b/handlers/junebug/junebug.go index 223c3749f..09cc1cf04 100644 --- a/handlers/junebug/junebug.go +++ b/handlers/junebug/junebug.go @@ -11,6 +11,7 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/httpx" "github.com/pkg/errors" ) @@ -221,7 +222,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann func (h *handler) RedactValues(ch courier.Channel) []string { return []string{ - handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + httpx.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), ch.StringConfigForKey(courier.ConfigSecret, ""), } } diff --git a/handlers/junebug/junebug_test.go b/handlers/junebug/junebug_test.go index 32efd3291..1d8dbf176 100644 --- a/handlers/junebug/junebug_test.go +++ b/handlers/junebug/junebug_test.go @@ -8,6 +8,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) var testChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JN", "2020", "US", map[string]interface{}{ @@ -217,6 +218,6 @@ var authenticatedSendTestCases = []ChannelSendTestCase{ } func TestSending(t *testing.T) { - RunChannelSendTestCases(t, testChannel, newHandler(), sendTestCases, []string{BasicAuth("user1", "pass1"), "sesame"}, nil) - RunChannelSendTestCases(t, authenticatedTestChannel, newHandler(), authenticatedSendTestCases, []string{BasicAuth("user1", "pass1"), "sesame"}, nil) + RunChannelSendTestCases(t, testChannel, newHandler(), sendTestCases, []string{httpx.BasicAuth("user1", "pass1"), "sesame"}, nil) + RunChannelSendTestCases(t, authenticatedTestChannel, newHandler(), authenticatedSendTestCases, []string{httpx.BasicAuth("user1", "pass1"), "sesame"}, nil) } diff --git a/handlers/playmobile/playmobile.go b/handlers/playmobile/playmobile.go index 6a9fe7c02..3f34b3874 100644 --- a/handlers/playmobile/playmobile.go +++ b/handlers/playmobile/playmobile.go @@ -12,6 +12,7 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/httpx" ) const ( @@ -209,6 +210,6 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann func (h *handler) RedactValues(ch courier.Channel) []string { return []string{ - handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + httpx.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), } } diff --git a/handlers/playmobile/playmobile_test.go b/handlers/playmobile/playmobile_test.go index 4c2c5b704..cb8db7ae4 100644 --- a/handlers/playmobile/playmobile_test.go +++ b/handlers/playmobile/playmobile_test.go @@ -7,6 +7,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) var testChannels = []courier.Channel{ @@ -186,5 +187,5 @@ func TestSending(t *testing.T) { "base_url": "http://91.204.239.42", }) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{BasicAuth("Username", "Password")}, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{httpx.BasicAuth("Username", "Password")}, nil) } diff --git a/handlers/plivo/plivo.go b/handlers/plivo/plivo.go index b3185fa93..88a648086 100644 --- a/handlers/plivo/plivo.go +++ b/handlers/plivo/plivo.go @@ -20,6 +20,7 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/httpx" ) var ( @@ -192,6 +193,6 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann func (h *handler) RedactValues(ch courier.Channel) []string { return []string{ - handlers.BasicAuth(ch.StringConfigForKey(configPlivoAuthID, ""), ch.StringConfigForKey(configPlivoAuthToken, "")), + httpx.BasicAuth(ch.StringConfigForKey(configPlivoAuthID, ""), ch.StringConfigForKey(configPlivoAuthToken, "")), } } diff --git a/handlers/plivo/plivo_test.go b/handlers/plivo/plivo_test.go index ee36efa43..ec947c8aa 100644 --- a/handlers/plivo/plivo_test.go +++ b/handlers/plivo/plivo_test.go @@ -7,6 +7,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) var testChannels = []courier.Channel{ @@ -132,5 +133,5 @@ func TestSending(t *testing.T) { }, ) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{BasicAuth("AuthID", "AuthToken")}, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{httpx.BasicAuth("AuthID", "AuthToken")}, nil) } diff --git a/handlers/start/start.go b/handlers/start/start.go index 1cba35479..c58b83ed4 100644 --- a/handlers/start/start.go +++ b/handlers/start/start.go @@ -16,6 +16,7 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/httpx" ) var ( @@ -183,6 +184,6 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann func (h *handler) RedactValues(ch courier.Channel) []string { return []string{ - handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + httpx.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), } } diff --git a/handlers/start/start_test.go b/handlers/start/start_test.go index b0381b42c..3f41dc83b 100644 --- a/handlers/start/start_test.go +++ b/handlers/start/start_test.go @@ -8,6 +8,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) var testChannels = []courier.Channel{ @@ -240,5 +241,5 @@ var defaultSendTestCases = []ChannelSendTestCase{ func TestSending(t *testing.T) { maxMsgLength = 160 var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ST", "2020", "UA", map[string]interface{}{"username": "Username", "password": "Password"}) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{BasicAuth("Username", "Password")}, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{httpx.BasicAuth("Username", "Password")}, nil) } diff --git a/handlers/thinq/thinq.go b/handlers/thinq/thinq.go index 50735b8cf..795ff19d0 100644 --- a/handlers/thinq/thinq.go +++ b/handlers/thinq/thinq.go @@ -13,6 +13,7 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/httpx" ) const configAccountID = "account_id" @@ -227,6 +228,6 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann func (h *handler) RedactValues(ch courier.Channel) []string { return []string{ - handlers.BasicAuth(ch.StringConfigForKey(configAPITokenUser, ""), ch.StringConfigForKey(configAPIToken, "")), + httpx.BasicAuth(ch.StringConfigForKey(configAPITokenUser, ""), ch.StringConfigForKey(configAPIToken, "")), } } diff --git a/handlers/thinq/thinq_test.go b/handlers/thinq/thinq_test.go index 03465fc48..b68c3512a 100644 --- a/handlers/thinq/thinq_test.go +++ b/handlers/thinq/thinq_test.go @@ -10,6 +10,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) var testChannels = []courier.Channel{ @@ -160,5 +161,5 @@ func TestSending(t *testing.T) { configAPITokenUser: "user1", configAPIToken: "sesame", }) - RunChannelSendTestCases(t, channel, newHandler(), sendTestCases, []string{BasicAuth("user1", "sesame")}, nil) + RunChannelSendTestCases(t, channel, newHandler(), sendTestCases, []string{httpx.BasicAuth("user1", "sesame")}, nil) } diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index 7f05b035c..0a8abed53 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -21,6 +21,7 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/utils" + "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/urns" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -309,7 +310,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann func (h *handler) RedactValues(ch courier.Channel) []string { return []string{ - handlers.BasicAuth(ch.StringConfigForKey(configAccountSID, ""), ch.StringConfigForKey(courier.ConfigAuthToken, "")), + httpx.BasicAuth(ch.StringConfigForKey(configAccountSID, ""), ch.StringConfigForKey(courier.ConfigAuthToken, "")), } } diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index bf6da4f4f..7a69181a8 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -10,6 +10,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/urns" ) @@ -687,10 +688,10 @@ func TestSending(t *testing.T) { configSendURL: "BASE_URL", }) - RunChannelSendTestCases(t, defaultChannel, newTWIMLHandler("T", "Twilio", true), defaultSendTestCases, []string{BasicAuth("accountSID", "authToken")}, nil) - RunChannelSendTestCases(t, tmsDefaultChannel, newTWIMLHandler("TMS", "Twilio Messaging Service", true), tmsDefaultSendTestCases, []string{BasicAuth("accountSID", "authToken")}, nil) - RunChannelSendTestCases(t, twDefaultChannel, newTWIMLHandler("TW", "TwiML", true), twDefaultSendTestCases, []string{BasicAuth("accountSID", "authToken")}, nil) - RunChannelSendTestCases(t, swChannel, newTWIMLHandler("SW", "SignalWire", false), swSendTestCases, []string{BasicAuth("accountSID", "authToken")}, nil) + RunChannelSendTestCases(t, defaultChannel, newTWIMLHandler("T", "Twilio", true), defaultSendTestCases, []string{httpx.BasicAuth("accountSID", "authToken")}, nil) + RunChannelSendTestCases(t, tmsDefaultChannel, newTWIMLHandler("TMS", "Twilio Messaging Service", true), tmsDefaultSendTestCases, []string{httpx.BasicAuth("accountSID", "authToken")}, nil) + RunChannelSendTestCases(t, twDefaultChannel, newTWIMLHandler("TW", "TwiML", true), twDefaultSendTestCases, []string{httpx.BasicAuth("accountSID", "authToken")}, nil) + RunChannelSendTestCases(t, swChannel, newTWIMLHandler("SW", "SignalWire", false), swSendTestCases, []string{httpx.BasicAuth("accountSID", "authToken")}, nil) waChannel := test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "SW", "+12065551212", "US", map[string]interface{}{ @@ -700,7 +701,7 @@ func TestSending(t *testing.T) { ) waChannel.SetScheme(urns.WhatsAppScheme) - RunChannelSendTestCases(t, waChannel, newTWIMLHandler("T", "Twilio Whatsapp", true), waSendTestCases, []string{BasicAuth("accountSID", "authToken")}, nil) + RunChannelSendTestCases(t, waChannel, newTWIMLHandler("T", "Twilio Whatsapp", true), waSendTestCases, []string{httpx.BasicAuth("accountSID", "authToken")}, nil) twaChannel := test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TWA", "+12065551212", "US", map[string]interface{}{ @@ -710,5 +711,5 @@ func TestSending(t *testing.T) { ) twaChannel.SetScheme(urns.WhatsAppScheme) - RunChannelSendTestCases(t, twaChannel, newTWIMLHandler("TWA", "Twilio Whatsapp", true), twaSendTestCases, []string{BasicAuth("accountSID", "authToken")}, nil) + RunChannelSendTestCases(t, twaChannel, newTWIMLHandler("TWA", "Twilio Whatsapp", true), twaSendTestCases, []string{httpx.BasicAuth("accountSID", "authToken")}, nil) } diff --git a/handlers/utils.go b/handlers/utils.go index 28aa1029b..13006ac6c 100644 --- a/handlers/utils.go +++ b/handlers/utils.go @@ -143,7 +143,3 @@ func StrictTelForCountry(number string, country string) (urns.URN, error) { return urn, nil } - -func BasicAuth(user, pass string) string { - return base64.StdEncoding.EncodeToString([]byte(user + ":" + pass)) -} diff --git a/handlers/zenviaold/zenviaold.go b/handlers/zenviaold/zenviaold.go index 7ce1fbb8c..49c578644 100644 --- a/handlers/zenviaold/zenviaold.go +++ b/handlers/zenviaold/zenviaold.go @@ -12,6 +12,7 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/httpx" "github.com/pkg/errors" ) @@ -215,6 +216,6 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann func (h *handler) RedactValues(ch courier.Channel) []string { return []string{ - handlers.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), + httpx.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), } } diff --git a/handlers/zenviaold/zenviaold_test.go b/handlers/zenviaold/zenviaold_test.go index 26526cb94..b80cca6d9 100644 --- a/handlers/zenviaold/zenviaold_test.go +++ b/handlers/zenviaold/zenviaold_test.go @@ -8,6 +8,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) var testChannels = []courier.Channel{ @@ -216,5 +217,5 @@ func TestSending(t *testing.T) { maxMsgLength = 160 var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ZV", "2020", "BR", map[string]interface{}{"username": "zv-username", "password": "zv-password"}) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{BasicAuth("zv-username", "zv-password")}, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{httpx.BasicAuth("zv-username", "zv-password")}, nil) } From f899966d298b01b1de3c9362ef75db4245d57826 Mon Sep 17 00:00:00 2001 From: Robi9 Date: Mon, 12 Sep 2022 12:51:56 -0300 Subject: [PATCH 154/294] Refactor condition --- handlers/facebookapp/facebookapp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index a9bd15551..32dc9ffd6 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -1172,7 +1172,7 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, } } - } else if i < len(msg.Attachments()) && len(qrs) == 0 || len(qrs) > 3 && i < len(msg.Attachments()) { + } else if i < len(msg.Attachments()) && (len(qrs) == 0 || len(qrs) > 3) { attType, attURL := handlers.SplitAttachment(msg.Attachments()[i]) attType = strings.Split(attType, "/")[0] if attType == "application" { From 8a7f6fd8428269477733fafe576b5f0945a315a4 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Tue, 13 Sep 2022 15:44:02 +0200 Subject: [PATCH 155/294] Adjust logging for WAC missing channel --- server.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/server.go b/server.go index 61e4fe503..f3df88a89 100644 --- a/server.go +++ b/server.go @@ -275,16 +275,17 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe defer cancel() r = r.WithContext(ctx) - // get the channel for this request - can be nil, e.g. FBA verification requests - channel, err := handler.GetChannel(ctx, r) + recorder, err := httpx.NewRecorder(r, w, true) if err != nil { - WriteError(ctx, w, r, err) + writeAndLogRequestError(ctx, w, r, nil, err) return } - recorder, err := httpx.NewRecorder(r, w, true) + // get the channel for this request - can be nil, e.g. FBA verification requests + channel, err := handler.GetChannel(ctx, r) if err != nil { - writeAndLogRequestError(ctx, w, r, channel, err) + logrus.WithError(err).WithField("request", string(recorder.Trace.RequestTrace)) + writeAndLogRequestError(ctx, recorder.ResponseWriter, r, channel, err) return } From ac12581e8c7c96ec680cf7d845e5c065869396bb Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 13 Sep 2022 09:14:52 -0500 Subject: [PATCH 156/294] Update CHANGELOG.md for v7.5.25 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 678bf9153..8f0148137 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +v7.5.25 +---------- + * Adjust logging for WAC missing channel + * Update to latest gocommon + * Implement redaction of channel logs + v7.5.24 ---------- * Adjust to use the cache by address correctly From 4f55e05c84ea9bcc2b51a525a0d8310905c28952 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 13 Sep 2022 10:35:48 -0500 Subject: [PATCH 157/294] Fix redaction on sends and add redaction of error messages --- channel_log.go | 2 +- handler_test.go | 33 ++++++++++++++++++++++++++++++--- sender.go | 2 +- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/channel_log.go b/channel_log.go index 09cd61f99..33ff124ba 100644 --- a/channel_log.go +++ b/channel_log.go @@ -92,7 +92,7 @@ func (l *ChannelLog) HTTP(t *httpx.Trace) { } func (l *ChannelLog) Error(err error) { - l.errors = append(l.errors, NewChannelError(err.Error(), "")) + l.errors = append(l.errors, NewChannelError(l.redactor(err.Error()), "")) } func (l *ChannelLog) End() { diff --git a/handler_test.go b/handler_test.go index 1a8f7ea6a..eaddfcbea 100644 --- a/handler_test.go +++ b/handler_test.go @@ -10,6 +10,7 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/urns" "github.com/stretchr/testify/assert" ) @@ -48,6 +49,14 @@ func (h *dummyHandler) Initialize(s courier.Server) error { // Send sends the given message, logging any HTTP calls or errors func (h *dummyHandler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { + // log a request that contains a header value that should be redacted + req, _ := httpx.NewRequest("GET", "http://dummy.com/send", nil, map[string]string{"Authorization": "Token sesame"}) + trace, _ := httpx.DoTrace(http.DefaultClient, req, nil, nil, 1024) + clog.HTTP(trace) + + // log an error than contains a value that should be redacted + clog.Error(errors.New("contains sesame seeds")) + return h.backend.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgSent, clog), nil } @@ -75,6 +84,13 @@ func testConfig() *courier.Config { } func TestHandling(t *testing.T) { + defer httpx.SetRequestor(httpx.DefaultRequestor) + httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ + "http://dummy.com/send": { + httpx.NewMockResponse(200, nil, []byte(`SENT`)), + }, + })) + assert := assert.New(t) // create our backend and server @@ -114,9 +130,20 @@ func TestHandling(t *testing.T) { time.Sleep(time.Second) // message should be marked as wired - assert.Equal(1, len(mb.WrittenMsgStatuses())) - assert.Equal(msg.ID(), mb.WrittenMsgStatuses()[0].ID()) - assert.Equal(courier.MsgSent, mb.WrittenMsgStatuses()[0].Status()) + assert.Len(mb.WrittenMsgStatuses(), 1) + status := mb.WrittenMsgStatuses()[0] + assert.Equal(msg.ID(), status.ID()) + assert.Equal(courier.MsgSent, status.Status()) + + assert.Len(mb.WrittenChannelLogs(), 1) + clog := mb.WrittenChannelLogs()[0] + assert.Equal([]courier.ChannelError{courier.NewChannelError("contains ********** seeds", "")}, clog.Errors()) + + assert.Len(clog.HTTPLogs(), 1) + + hlog := clog.HTTPLogs()[0] + assert.Equal("http://dummy.com/send", hlog.URL) + assert.Equal("GET /send HTTP/1.1\r\nHost: dummy.com\r\nUser-Agent: Go-http-client/1.1\r\nAuthorization: Token **********\r\nAccept-Encoding: gzip\r\n\r\n", hlog.Request) mb.Reset() diff --git a/sender.go b/sender.go index 0ad8a2298..db486346a 100644 --- a/sender.go +++ b/sender.go @@ -191,7 +191,7 @@ func (w *Sender) sendMessage(msg Msg) { var redactValues []string handler := server.GetHandler(msg.Channel()) if handler != nil { - handler.RedactValues(msg.Channel()) + redactValues = handler.RedactValues(msg.Channel()) } clog := NewChannelLogForSend(msg, redactValues) From 5b05d04a3926a85862efdf7d1ac6efd729228a24 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 13 Sep 2022 10:45:24 -0500 Subject: [PATCH 158/294] Fix junebug redaction values --- handlers/junebug/junebug.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/handlers/junebug/junebug.go b/handlers/junebug/junebug.go index 09cc1cf04..dafa36b3c 100644 --- a/handlers/junebug/junebug.go +++ b/handlers/junebug/junebug.go @@ -221,8 +221,12 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } func (h *handler) RedactValues(ch courier.Channel) []string { - return []string{ + vals := []string{ httpx.BasicAuth(ch.StringConfigForKey(courier.ConfigUsername, ""), ch.StringConfigForKey(courier.ConfigPassword, "")), - ch.StringConfigForKey(courier.ConfigSecret, ""), } + secret := ch.StringConfigForKey(courier.ConfigSecret, "") + if secret != "" { + vals = append(vals, secret) + } + return vals } From 98cdda766bf2dff56146374c6d3c0048c840f947 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 13 Sep 2022 10:57:41 -0500 Subject: [PATCH 159/294] Update CHANGELOG.md for v7.5.26 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f0148137..98524174d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.26 +---------- + * Fix junebug redaction values + * Fix redaction on sends and add redaction of error messages + v7.5.25 ---------- * Adjust logging for WAC missing channel From 87308334f232629a5ad1f94dbf819e5551fe381c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 13 Sep 2022 11:08:42 -0500 Subject: [PATCH 160/294] Fix server logging when channel is nil --- server.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/server.go b/server.go index f8ab3f574..e74e4f5c3 100644 --- a/server.go +++ b/server.go @@ -279,12 +279,17 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe return } + var channelUUID ChannelUUID + if channel != nil { + channelUUID = channel.UUID() + } + defer func() { // catch any panics and recover panicLog := recover() if panicLog != nil { debug.PrintStack() - logrus.WithError(err).WithField("channel_uuid", channel.UUID()).WithField("request", string(recorder.Trace.RequestTrace)).WithField("trace", panicLog).Error("panic handling request") + logrus.WithError(err).WithField("channel_uuid", channelUUID).WithField("request", string(recorder.Trace.RequestTrace)).WithField("trace", panicLog).Error("panic handling request") writeAndLogRequestError(ctx, recorder.ResponseWriter, r, channel, errors.New("panic handling msg")) } }() @@ -297,13 +302,13 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe // if we received an error, write it out and report it if hErr != nil { - logrus.WithError(hErr).WithField("channel_uuid", channel.UUID()).WithField("request", string(recorder.Trace.RequestTrace)).Error("error handling request") + logrus.WithError(hErr).WithField("channel_uuid", channelUUID).WithField("request", string(recorder.Trace.RequestTrace)).Error("error handling request") writeAndLogRequestError(ctx, recorder.ResponseWriter, r, channel, hErr) } // end recording of the request so that we have a response trace if err := recorder.End(); err != nil { - logrus.WithError(err).WithField("channel_uuid", channel.UUID()).WithField("request", string(recorder.Trace.RequestTrace)).Error("error receording request") + logrus.WithError(err).WithField("channel_uuid", channelUUID).WithField("request", string(recorder.Trace.RequestTrace)).Error("error recording request") writeAndLogRequestError(ctx, w, r, channel, err) } From dd7a5daed128923b85735ff9c1b00cba23b25fbe Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 13 Sep 2022 11:20:52 -0500 Subject: [PATCH 161/294] Update CHANGELOG.md for v7.5.27 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98524174d..70dbc1a31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.27 +---------- + * Fix server logging when channel is nil + v7.5.26 ---------- * Fix junebug redaction values From 7d3be1000ada6be21aa71f171bf41cee46c7513a Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 14 Sep 2022 14:55:09 +0200 Subject: [PATCH 162/294] Add test for invalid request signature for WAC --- handlers/facebookapp/facebookapp_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index e4aa54795..d45d4959a 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -694,6 +694,16 @@ var testCasesWAC = []ChannelHandleTestCase{ ExpectedRespBody: "invalid timestamp", PrepRequest: addValidSignature, }, + { + Label: "Receive Message WAC invalid signature", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/helloWAC.json")), + ExpectedRespStatus: 400, + ExpectedRespBody: "invalid request signature", + NoQueueErrorCheck: true, + NoInvalidChannelCheck: true, + PrepRequest: addInvalidSignature, + }, { Label: "Receive Valid Status", URL: wacReceiveURL, From eb76749cc7887b10d9c3c95e23d548a542d2768b Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 14 Sep 2022 16:08:23 +0200 Subject: [PATCH 163/294] Meta channels webhooks requests, should always return 200 status --- handlers/facebookapp/facebookapp.go | 24 ++++++++---- handlers/facebookapp/facebookapp_test.go | 48 ++++++++++++------------ server.go | 9 ++++- 3 files changed, 48 insertions(+), 33 deletions(-) diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index f303c31c1..35029f831 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -360,13 +360,15 @@ func resolveMediaURL(mediaID string, token string, clog *courier.ChannelLog) (st func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { err := h.validateSignature(r) if err != nil { - return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) + courier.LogRequestError(r, channel, err) + return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring request, invalid request signature") } payload := &moPayload{} err = handlers.DecodeAndValidateJSON(payload, r) if err != nil { - return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) + courier.LogRequestError(r, channel, err) + return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring request, invalid JSON") } // is not a 'page' and 'instagram' object? ignore it @@ -423,13 +425,15 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri // create our date from the timestamp ts, err := strconv.ParseInt(msg.Timestamp, 10, 64) if err != nil { - return nil, nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, fmt.Errorf("invalid timestamp: %s", msg.Timestamp)) + courier.LogRequestError(r, channel, err) + return nil, nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, fmt.Sprintf("ignoring request, invalid timestamp: %s", msg.Timestamp)) } date := time.Unix(ts, 0).UTC() urn, err := urns.NewWhatsAppURN(msg.From) if err != nil { - return nil, nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) + courier.LogRequestError(r, channel, err) + return nil, nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring request, invalid whatsapp id") } text := "" @@ -497,7 +501,8 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri if waIgnoreStatuses[status.Status] { data = append(data, courier.NewInfoData(fmt.Sprintf("ignoring status: %s", status.Status))) } else { - handlers.WriteAndLogRequestError(ctx, h, channel, w, r, fmt.Errorf("unknown status: %s", status.Status)) + courier.LogRequestError(r, channel, fmt.Errorf("unknown status: %s", status.Status)) + handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, fmt.Sprintf("unknown status: %s", status.Status)) } continue } @@ -564,12 +569,14 @@ func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel c if payload.Object == "instagram" { urn, err = urns.NewInstagramURN(sender) if err != nil { - return nil, nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) + courier.LogRequestError(r, channel, err) + return nil, nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring request, invalid instagram id") } } else { urn, err = urns.NewFacebookURN(sender) if err != nil { - return nil, nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) + courier.LogRequestError(r, channel, err) + return nil, nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring request, invalid facebook id") } } @@ -583,7 +590,8 @@ func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel c if msg.OptIn.UserRef != "" { urn, err = urns.NewFacebookURN(urns.FacebookRefPrefix + msg.OptIn.UserRef) if err != nil { - return nil, nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) + courier.LogRequestError(r, channel, err) + return nil, nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring request") } } diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index d45d4959a..1cea3bb76 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -49,8 +49,8 @@ var testCasesFBA = []ChannelHandleTestCase{ Label: "Receive Invalid Signature", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), - ExpectedRespStatus: 400, - ExpectedRespBody: "invalid request signature", + ExpectedRespStatus: 200, + ExpectedRespBody: "ignoring request, invalid request signature", PrepRequest: addInvalidSignature, }, { @@ -205,7 +205,7 @@ var testCasesFBA = []ChannelHandleTestCase{ Label: "Not Page", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/notPage.json")), - ExpectedRespStatus: 400, + ExpectedRespStatus: 200, ExpectedRespBody: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notpage", PrepRequest: addValidSignature, }, @@ -213,7 +213,7 @@ var testCasesFBA = []ChannelHandleTestCase{ Label: "No Entries", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/noEntriesFBA.json")), - ExpectedRespStatus: 400, + ExpectedRespStatus: 200, ExpectedRespBody: "no entries found", PrepRequest: addValidSignature, }, @@ -237,16 +237,16 @@ var testCasesFBA = []ChannelHandleTestCase{ Label: "Not JSON", URL: "/c/fba/receive", Data: "not JSON", - ExpectedRespStatus: 400, - ExpectedRespBody: "Error", + ExpectedRespStatus: 200, + ExpectedRespBody: "unable to parse request JSON", PrepRequest: addValidSignature, }, { Label: "Invalid URN", URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/invalidURNFBA.json")), - ExpectedRespStatus: 400, - ExpectedRespBody: "invalid facebook id", + ExpectedRespStatus: 200, + ExpectedRespBody: "ignoring request, invalid facebook id", PrepRequest: addValidSignature, }, } @@ -270,8 +270,8 @@ var testCasesIG = []ChannelHandleTestCase{ Label: "Receive Invalid Signature", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), - ExpectedRespStatus: 400, - ExpectedRespBody: "invalid request signature", + ExpectedRespStatus: 200, + ExpectedRespBody: "ignoring request, invalid request signature", PrepRequest: addInvalidSignature, }, { @@ -343,7 +343,7 @@ var testCasesIG = []ChannelHandleTestCase{ Label: "No Entries", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/noEntriesIG.json")), - ExpectedRespStatus: 400, + ExpectedRespStatus: 200, ExpectedRespBody: "no entries found", PrepRequest: addValidSignature, }, @@ -351,7 +351,7 @@ var testCasesIG = []ChannelHandleTestCase{ Label: "Not Instagram", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/notInstagram.json")), - ExpectedRespStatus: 400, + ExpectedRespStatus: 200, ExpectedRespBody: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notinstagram", PrepRequest: addValidSignature, }, @@ -375,16 +375,16 @@ var testCasesIG = []ChannelHandleTestCase{ Label: "Not JSON", URL: "/c/ig/receive", Data: "not JSON", - ExpectedRespStatus: 400, - ExpectedRespBody: "Error", + ExpectedRespStatus: 200, + ExpectedRespBody: "unable to parse request JSON", PrepRequest: addValidSignature, }, { Label: "Invalid URN", URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/invalidURNIG.json")), - ExpectedRespStatus: 400, - ExpectedRespBody: "invalid instagram id", + ExpectedRespStatus: 200, + ExpectedRespBody: "ignoring request, invalid instagram id", PrepRequest: addValidSignature, }, { @@ -674,7 +674,7 @@ var testCasesWAC = []ChannelHandleTestCase{ Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: "not json", - ExpectedRespStatus: 400, + ExpectedRespStatus: 200, ExpectedRespBody: "unable to parse", PrepRequest: addValidSignature, }, @@ -682,24 +682,24 @@ var testCasesWAC = []ChannelHandleTestCase{ Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidFrom.json")), - ExpectedRespStatus: 400, - ExpectedRespBody: "invalid whatsapp id", + ExpectedRespStatus: 200, + ExpectedRespBody: "ignoring request, invalid whatsapp id", PrepRequest: addValidSignature, }, { Label: "Receive Invalid JSON", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidTimestamp.json")), - ExpectedRespStatus: 400, - ExpectedRespBody: "invalid timestamp", + ExpectedRespStatus: 200, + ExpectedRespBody: "ignoring request, invalid timestamp", PrepRequest: addValidSignature, }, { Label: "Receive Message WAC invalid signature", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/helloWAC.json")), - ExpectedRespStatus: 400, - ExpectedRespBody: "invalid request signature", + ExpectedRespStatus: 200, + ExpectedRespBody: "ignoring request, invalid request signature", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, PrepRequest: addInvalidSignature, @@ -718,7 +718,7 @@ var testCasesWAC = []ChannelHandleTestCase{ Label: "Receive Invalid Status", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidStatusWAC.json")), - ExpectedRespStatus: 400, + ExpectedRespStatus: 200, ExpectedRespBody: `"unknown status: in_orbit"`, PrepRequest: addValidSignature, }, diff --git a/server.go b/server.go index e74e4f5c3..5c7c91089 100644 --- a/server.go +++ b/server.go @@ -274,7 +274,14 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe // get the channel for this request - can be nil, e.g. FBA verification requests channel, err := handler.GetChannel(ctx, r) if err != nil { - logrus.WithError(err).WithField("request", string(recorder.Trace.RequestTrace)) + + // webhooks for FBA, IG and WAC should always return 200 + if !handler.UseChannelRouteUUID() { + logrus.WithError(err).WithField("request", string(recorder.Trace.RequestTrace)) + WriteIgnored(ctx, recorder.ResponseWriter, r, err.Error()) + return + } + writeAndLogRequestError(ctx, recorder.ResponseWriter, r, channel, err) return } From dc58fa092cc40b0f227ca3287755882effa9dc5b Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 14 Sep 2022 17:35:42 +0200 Subject: [PATCH 164/294] Add handler ErrorResponseStatus --- handler.go | 1 + handler_test.go | 1 + handlers/base.go | 5 ++++ handlers/facebookapp/facebookapp.go | 34 +++++++++++++----------- handlers/facebookapp/facebookapp_test.go | 14 +++++----- server.go | 4 +-- 6 files changed, 34 insertions(+), 25 deletions(-) diff --git a/handler.go b/handler.go index 3d99908a8..12fad794a 100644 --- a/handler.go +++ b/handler.go @@ -24,6 +24,7 @@ type ChannelHandler interface { ChannelType() ChannelType ChannelName() string UseChannelRouteUUID() bool + ErrorResponseStatus() int RedactValues(Channel) []string GetChannel(context.Context, *http.Request) (Channel, error) Send(context.Context, Msg, *ChannelLog) (MsgStatus, error) diff --git a/handler_test.go b/handler_test.go index eaddfcbea..a336ac6d7 100644 --- a/handler_test.go +++ b/handler_test.go @@ -33,6 +33,7 @@ func (h *dummyHandler) ChannelName() string { return "Dummy Ha func (h *dummyHandler) ChannelType() courier.ChannelType { return courier.ChannelType("DM") } func (h *dummyHandler) UseChannelRouteUUID() bool { return true } func (h *dummyHandler) RedactValues(courier.Channel) []string { return []string{"sesame"} } +func (h *dummyHandler) ErrorResponseStatus() int { return 400 } func (h *dummyHandler) GetChannel(ctx context.Context, r *http.Request) (courier.Channel, error) { dmChannel := test.NewMockChannel("e4bb1578-29da-4fa5-a214-9da19dd24230", "DM", "2020", "US", map[string]interface{}{}) diff --git a/handlers/base.go b/handlers/base.go index f07d061f2..058d97726 100644 --- a/handlers/base.go +++ b/handlers/base.go @@ -66,6 +66,11 @@ func (h *BaseHandler) UseChannelRouteUUID() bool { return h.useChannelRouteUUID } +// ErrorResponseStatus() return the response status code for errors +func (h *BaseHandler) ErrorResponseStatus() int { + return 400 +} + func (h *BaseHandler) RedactValues(ch courier.Channel) []string { if ch == nil { return nil diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 35029f831..fa44c83da 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -270,6 +270,16 @@ func (h *handler) RedactValues(ch courier.Channel) []string { return vals } +// WriteRequestError writes the passed in error to our response writer +func (h *handler) WriteRequestError(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) error { + return courier.WriteIgnored(ctx, w, r, fmt.Sprintf("ignoring request, %s", err.Error())) +} + +// ErrorResponseStatus() return the response status code for errors +func (h *handler) ErrorResponseStatus() int { + return 200 +} + // GetChannel returns the channel func (h *handler) GetChannel(ctx context.Context, r *http.Request) (courier.Channel, error) { if r.Method == http.MethodGet { @@ -360,15 +370,13 @@ func resolveMediaURL(mediaID string, token string, clog *courier.ChannelLog) (st func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { err := h.validateSignature(r) if err != nil { - courier.LogRequestError(r, channel, err) - return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring request, invalid request signature") + return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } payload := &moPayload{} err = handlers.DecodeAndValidateJSON(payload, r) if err != nil { - courier.LogRequestError(r, channel, err) - return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring request, invalid JSON") + return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } // is not a 'page' and 'instagram' object? ignore it @@ -425,15 +433,13 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri // create our date from the timestamp ts, err := strconv.ParseInt(msg.Timestamp, 10, 64) if err != nil { - courier.LogRequestError(r, channel, err) - return nil, nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, fmt.Sprintf("ignoring request, invalid timestamp: %s", msg.Timestamp)) + return nil, nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, fmt.Errorf("invalid timestamp: %s", msg.Timestamp)) } date := time.Unix(ts, 0).UTC() urn, err := urns.NewWhatsAppURN(msg.From) if err != nil { - courier.LogRequestError(r, channel, err) - return nil, nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring request, invalid whatsapp id") + return nil, nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } text := "" @@ -501,8 +507,7 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri if waIgnoreStatuses[status.Status] { data = append(data, courier.NewInfoData(fmt.Sprintf("ignoring status: %s", status.Status))) } else { - courier.LogRequestError(r, channel, fmt.Errorf("unknown status: %s", status.Status)) - handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, fmt.Sprintf("unknown status: %s", status.Status)) + handlers.WriteAndLogRequestError(ctx, h, channel, w, r, fmt.Errorf("unknown status: %s", status.Status)) } continue } @@ -569,14 +574,12 @@ func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel c if payload.Object == "instagram" { urn, err = urns.NewInstagramURN(sender) if err != nil { - courier.LogRequestError(r, channel, err) - return nil, nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring request, invalid instagram id") + return nil, nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } } else { urn, err = urns.NewFacebookURN(sender) if err != nil { - courier.LogRequestError(r, channel, err) - return nil, nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring request, invalid facebook id") + return nil, nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } } @@ -590,8 +593,7 @@ func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel c if msg.OptIn.UserRef != "" { urn, err = urns.NewFacebookURN(urns.FacebookRefPrefix + msg.OptIn.UserRef) if err != nil { - courier.LogRequestError(r, channel, err) - return nil, nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring request") + return nil, nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } } diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 1cea3bb76..48c8f481d 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -719,7 +719,7 @@ var testCasesWAC = []ChannelHandleTestCase{ URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidStatusWAC.json")), ExpectedRespStatus: 200, - ExpectedRespBody: `"unknown status: in_orbit"`, + ExpectedRespBody: `"ignoring request, unknown status: in_orbit"`, PrepRequest: addValidSignature, }, { @@ -833,19 +833,19 @@ func TestVerify(t *testing.T) { { Label: "Verify No Mode", URL: "/c/fba/receive", - ExpectedRespStatus: 400, + ExpectedRespStatus: 200, ExpectedRespBody: "unknown request", }, { Label: "Verify No Secret", URL: "/c/fba/receive?hub.mode=subscribe", - ExpectedRespStatus: 400, + ExpectedRespStatus: 200, ExpectedRespBody: "token does not match secret", }, { Label: "Invalid Secret", URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=blah", - ExpectedRespStatus: 400, + ExpectedRespStatus: 200, ExpectedRespBody: "token does not match secret", }, { @@ -868,19 +868,19 @@ func TestVerify(t *testing.T) { { Label: "Verify No Mode", URL: "/c/ig/receive", - ExpectedRespStatus: 400, + ExpectedRespStatus: 200, ExpectedRespBody: "unknown request", }, { Label: "Verify No Secret", URL: "/c/ig/receive?hub.mode=subscribe", - ExpectedRespStatus: 400, + ExpectedRespStatus: 200, ExpectedRespBody: "token does not match secret", }, { Label: "Invalid Secret", URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=blah", - ExpectedRespStatus: 400, + ExpectedRespStatus: 200, ExpectedRespBody: "token does not match secret", }, { diff --git a/server.go b/server.go index 5c7c91089..a58d4f822 100644 --- a/server.go +++ b/server.go @@ -276,9 +276,9 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe if err != nil { // webhooks for FBA, IG and WAC should always return 200 - if !handler.UseChannelRouteUUID() { + if handler.ErrorResponseStatus() == 200 { logrus.WithError(err).WithField("request", string(recorder.Trace.RequestTrace)) - WriteIgnored(ctx, recorder.ResponseWriter, r, err.Error()) + WriteIgnored(ctx, recorder.ResponseWriter, r, fmt.Sprintf("ignoring request, %s", err.Error())) return } From 09fcb6550e6d0efd53a028d2969acdf9a8c61ac0 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Thu, 15 Sep 2022 12:12:23 +0200 Subject: [PATCH 165/294] Update to use SHA256 signature for FBA payload --- handlers/facebookapp/facebookapp.go | 14 ++++++++------ handlers/facebookapp/facebookapp_test.go | 8 ++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index f303c31c1..8314a87a1 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -4,7 +4,7 @@ import ( "bytes" "context" "crypto/hmac" - "crypto/sha1" + "crypto/sha256" "encoding/hex" "encoding/json" "fmt" @@ -27,7 +27,9 @@ var ( sendURL = "https://graph.facebook.com/v12.0/me/messages" graphURL = "https://graph.facebook.com/v12.0/" - signatureHeader = "X-Hub-Signature" + signatureHeader = "X-Hub-Signature-256" + + maxRequestBodyBytes int64 = 500000 // max for the body maxMsgLength = 1000 @@ -1367,7 +1369,7 @@ func (h *handler) validateSignature(r *http.Request) error { } appSecret := h.Server().Config().FacebookApplicationSecret - body, err := handlers.ReadBody(r, 100000) + body, err := handlers.ReadBody(r, maxRequestBodyBytes) if err != nil { return fmt.Errorf("unable to read request body: %s", err) } @@ -1378,8 +1380,8 @@ func (h *handler) validateSignature(r *http.Request) error { } signature := "" - if len(headerSignature) == 45 && strings.HasPrefix(headerSignature, "sha1=") { - signature = strings.TrimPrefix(headerSignature, "sha1=") + if len(headerSignature) == 71 && strings.HasPrefix(headerSignature, "sha256=") { + signature = strings.TrimPrefix(headerSignature, "sha256=") } // compare signatures in way that isn't sensitive to a timing attack @@ -1395,7 +1397,7 @@ func fbCalculateSignature(appSecret string, body []byte) (string, error) { buffer.Write(body) // hash with SHA1 - mac := hmac.New(sha1.New, []byte(appSecret)) + mac := hmac.New(sha256.New, []byte(appSecret)) mac.Write(buffer.Bytes()) return hex.EncodeToString(mac.Sum(nil)), nil diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index e4aa54795..97c965b15 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -406,9 +406,9 @@ var testCasesIG = []ChannelHandleTestCase{ } func addValidSignature(r *http.Request) { - body, _ := ReadBody(r, 100000) + body, _ := ReadBody(r, maxRequestBodyBytes) sig, _ := fbCalculateSignature("fb_app_secret", body) - r.Header.Set(signatureHeader, fmt.Sprintf("sha1=%s", string(sig))) + r.Header.Set(signatureHeader, fmt.Sprintf("sha256=%s", string(sig))) } func addInvalidSignature(r *http.Request) { @@ -1339,11 +1339,11 @@ func TestSigning(t *testing.T) { }{ { "hello world", - "308de7627fe19e92294c4572a7f831bc1002809d", + "f39034b29165ec6a5104d9aef27266484ab26c8caa7bca8bcb2dd02e8be61b17", }, { "hello world2", - "ab6f902b58b9944032d4a960f470d7a8ebfd12b7", + "60905fdf409d0b4f721e99f6f25b31567a68a6b45e933d814e17a246be4c5a53", }, } From 0d566d434875d183d0acda08fe7b7eee6d10d120 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Thu, 15 Sep 2022 16:22:13 +0200 Subject: [PATCH 166/294] Increase the maxRequestBodyBytes to 1MB --- handlers/facebookapp/facebookapp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 8314a87a1..e510abf0a 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -29,7 +29,7 @@ var ( signatureHeader = "X-Hub-Signature-256" - maxRequestBodyBytes int64 = 500000 + maxRequestBodyBytes int64 = 1024 * 1024 // max for the body maxMsgLength = 1000 From 67b42850e5c3718d454436d6dee059b2a2caee24 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 15 Sep 2022 09:56:53 -0500 Subject: [PATCH 167/294] Minor cleanup in handlers/test.go --- handlers/test.go | 291 +++++++++++++++++++++++------------------------ 1 file changed, 145 insertions(+), 146 deletions(-) diff --git a/handlers/test.go b/handlers/test.go index e2c5c67f7..0c9656c79 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -53,9 +53,6 @@ type ChannelHandleTestCase struct { ExpectedEventExtra map[string]interface{} } -// SendPrepFunc allows test cases to modify the channel, msg or server before a message is sent -type SendPrepFunc func(*httptest.Server, courier.ChannelHandler, courier.Channel, courier.Msg) - // MockedRequest is a fake HTTP request type MockedRequest struct { Method string @@ -69,44 +66,8 @@ func (m MockedRequest) Matches(r *http.Request, body []byte) bool { return m.Method == r.Method && m.Path == r.URL.Path && m.RawQuery == r.URL.RawQuery && (m.Body == string(body) || (m.BodyContains != "" && strings.Contains(string(body), m.BodyContains))) } -// ChannelSendTestCase defines the test values for a particular test case -type ChannelSendTestCase struct { - Label string - SendPrep SendPrepFunc - - MsgText string - MsgURN string - MsgURNAuth string - MsgAttachments []string - MsgQuickReplies []string - MsgTopic string - MsgHighPriority bool - MsgResponseToExternalID string - MsgMetadata json.RawMessage - MsgFlow *courier.FlowReference - - MockResponseStatus int - MockResponseBody string - MockResponses map[MockedRequest]*httpx.MockResponse - - ExpectedRequestPath string - ExpectedURLParams map[string]string - ExpectedPostParams map[string]string - ExpectedRequestBody string - ExpectedHeaders map[string]string - ExpectedMsgStatus courier.MsgStatusValue - ExpectedExternalID string - ExpectedErrors []courier.ChannelError - ExpectedStopEvent bool - ExpectedContactURNs map[string]bool - ExpectedNewURN string -} - -// Sp is a utility method to get the pointer to the passed in string -func Sp(s string) *string { return &s } - // utility method to make a request to a handler URL -func testHandlerRequest(tb testing.TB, s courier.Server, path string, headers map[string]string, data string, multipartFormFields map[string]string, expectedStatus int, expectedBody *string, requestPrepFunc RequestPrepFunc) string { +func testHandlerRequest(tb testing.TB, s courier.Server, path string, headers map[string]string, data string, multipartFormFields map[string]string, expectedStatus int, expectedBody string, requestPrepFunc RequestPrepFunc) string { var req *http.Request var err error url := fmt.Sprintf("https://%s%s", s.Config().Domain, path) @@ -159,8 +120,8 @@ func testHandlerRequest(tb testing.TB, s courier.Server, path string, headers ma require.Equal(tb, expectedStatus, rr.Code, fmt.Sprintf("incorrect status code with response: %s", body)) - if expectedBody != nil { - require.Contains(tb, body, *expectedBody) + if expectedBody != "" { + assert.Contains(tb, body, expectedBody) } return body @@ -181,6 +142,144 @@ func newServer(backend courier.Backend) courier.Server { } +// RunChannelTestCases runs all the passed in tests cases for the passed in channel configurations +func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler courier.ChannelHandler, testCases []ChannelHandleTestCase) { + mb := test.NewMockBackend() + s := newServer(mb) + + for _, ch := range channels { + mb.AddChannel(ch) + } + handler.Initialize(s) + + for _, tc := range testCases { + t.Run(tc.Label, func(t *testing.T) { + require := require.New(t) + + mb.Reset() + + testHandlerRequest(t, s, tc.URL, tc.Headers, tc.Data, tc.MultipartForm, tc.ExpectedRespStatus, tc.ExpectedRespBody, tc.PrepRequest) + + if tc.ExpectedMsgText != nil || tc.ExpectedAttachments != nil { + require.Len(mb.WrittenMsgs(), 1, "expected a msg to be written") + msg := mb.WrittenMsgs()[0] + + if tc.ExpectedMsgText != nil { + assert.Equal(t, *tc.ExpectedMsgText, msg.Text()) + } + if len(tc.ExpectedAttachments) > 0 { + assert.Equal(t, tc.ExpectedAttachments, msg.Attachments()) + } + if !tc.ExpectedDate.IsZero() { + assert.Equal(t, tc.ExpectedDate.Local(), msg.ReceivedOn().Local()) + } + if tc.ExpectedExternalID != "" { + assert.Equal(t, tc.ExpectedExternalID, msg.ExternalID()) + } + assert.Equal(t, tc.ExpectedURN, msg.URN()) + assert.Equal(t, tc.ExpectedURNAuth, msg.URNAuth()) + } else { + assert.Empty(t, mb.WrittenMsgs(), "unexpected msg written") + } + + if tc.ExpectedMsgStatus != "" { + // TODO find better way to test statuses because some channels (e.g. infobip) can create multiple statuses in one call + require.Greater(len(mb.WrittenMsgStatuses()), 0, "expected a msg status to be written") + status := mb.WrittenMsgStatuses()[len(mb.WrittenMsgStatuses())-1] + + assert.Equal(t, tc.ExpectedMsgStatus, status.Status()) + + if tc.ExpectedExternalID != "" { + assert.Equal(t, tc.ExpectedExternalID, status.ExternalID()) + } + if tc.ExpectedMsgID != 0 { + assert.Equal(t, tc.ExpectedMsgID, int64(status.ID())) + } + } else { + assert.Empty(t, mb.WrittenMsgStatuses(), "unexpected msg status written") + } + + if tc.ExpectedEvent != "" { + require.Len(mb.WrittenChannelEvents(), 1, "expected a channel event to be written") + event := mb.WrittenChannelEvents()[0] + + assert.Equal(t, tc.ExpectedEvent, event.EventType()) + assert.Equal(t, tc.ExpectedEventExtra, event.Extra()) + assert.Equal(t, tc.ExpectedURN, event.URN()) + + if !tc.ExpectedDate.IsZero() { + assert.Equal(t, tc.ExpectedDate, event.OccurredOn()) + } + } else { + assert.Empty(t, mb.WrittenChannelEvents(), "unexpected channel event written") + } + + if tc.ExpectedContactName != nil { + require.Equal(*tc.ExpectedContactName, mb.LastContactName()) + } + + // if we're expecting a message, status or event, check we have a log for it + if tc.ExpectedMsgText != nil || tc.ExpectedMsgStatus != "" || tc.ExpectedEvent != "" { + assert.Greater(t, len(mb.WrittenChannelLogs()), 0, "expected at least one channel log") + } + }) + } + + // check non-channel specific error conditions against first test case + validCase := testCases[0] + + if !validCase.NoQueueErrorCheck { + t.Run("Queue Error", func(t *testing.T) { + mb.SetErrorOnQueue(true) + defer mb.SetErrorOnQueue(false) + testHandlerRequest(t, s, validCase.URL, validCase.Headers, validCase.Data, validCase.MultipartForm, 400, "unable to queue message", validCase.PrepRequest) + }) + } + + if !validCase.NoInvalidChannelCheck { + t.Run("Receive With Invalid Channel", func(t *testing.T) { + mb.ClearChannels() + testHandlerRequest(t, s, validCase.URL, validCase.Headers, validCase.Data, validCase.MultipartForm, 400, "channel not found", validCase.PrepRequest) + }) + } +} + +// SendPrepFunc allows test cases to modify the channel, msg or server before a message is sent +type SendPrepFunc func(*httptest.Server, courier.ChannelHandler, courier.Channel, courier.Msg) + +// ChannelSendTestCase defines the test values for a particular test case +type ChannelSendTestCase struct { + Label string + SendPrep SendPrepFunc + + MsgText string + MsgURN string + MsgURNAuth string + MsgAttachments []string + MsgQuickReplies []string + MsgTopic string + MsgHighPriority bool + MsgResponseToExternalID string + MsgMetadata json.RawMessage + MsgFlow *courier.FlowReference + + MockResponseStatus int + MockResponseBody string + MockResponses map[MockedRequest]*httpx.MockResponse + + ExpectedRequestPath string + ExpectedURLParams map[string]string + ExpectedPostParams map[string]string + ExpectedRequestBody string + ExpectedHeaders map[string]string + ExpectedMsgStatus courier.MsgStatusValue + ExpectedExternalID string + ExpectedErrors []courier.ChannelError + ExpectedStopEvent bool + ExpectedContactURNs map[string]bool + ExpectedNewURN string +} + // RunChannelSendTestCases runs all the passed in test cases against the channel func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler courier.ChannelHandler, testCases []ChannelSendTestCase, checkRedacted []string, setupBackend func(*test.MockBackend)) { mb := test.NewMockBackend() @@ -333,109 +432,6 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour AssertChannelLogRedaction(t, clog, checkRedacted) }) } - -} - -// RunChannelTestCases runs all the passed in tests cases for the passed in channel configurations -func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler courier.ChannelHandler, testCases []ChannelHandleTestCase) { - mb := test.NewMockBackend() - s := newServer(mb) - - for _, ch := range channels { - mb.AddChannel(ch) - } - handler.Initialize(s) - - for _, tc := range testCases { - t.Run(tc.Label, func(t *testing.T) { - require := require.New(t) - - mb.Reset() - - testHandlerRequest(t, s, tc.URL, tc.Headers, tc.Data, tc.MultipartForm, tc.ExpectedRespStatus, &tc.ExpectedRespBody, tc.PrepRequest) - - if tc.ExpectedMsgText != nil || tc.ExpectedAttachments != nil { - require.Len(mb.WrittenMsgs(), 1, "expected a msg to be written") - msg := mb.WrittenMsgs()[0] - - if tc.ExpectedMsgText != nil { - assert.Equal(t, *tc.ExpectedMsgText, msg.Text()) - } - if len(tc.ExpectedAttachments) > 0 { - assert.Equal(t, tc.ExpectedAttachments, msg.Attachments()) - } - if !tc.ExpectedDate.IsZero() { - assert.Equal(t, tc.ExpectedDate.Local(), msg.ReceivedOn().Local()) - } - if tc.ExpectedExternalID != "" { - assert.Equal(t, tc.ExpectedExternalID, msg.ExternalID()) - } - assert.Equal(t, tc.ExpectedURN, msg.URN()) - assert.Equal(t, tc.ExpectedURNAuth, msg.URNAuth()) - } else { - assert.Empty(t, mb.WrittenMsgs(), "unexpected msg written") - } - - if tc.ExpectedMsgStatus != "" { - // TODO find better way to test statuses because some channels (e.g. infobip) can create multiple statuses in one call - require.Greater(len(mb.WrittenMsgStatuses()), 0, "expected a msg status to be written") - status := mb.WrittenMsgStatuses()[len(mb.WrittenMsgStatuses())-1] - - assert.Equal(t, tc.ExpectedMsgStatus, status.Status()) - - if tc.ExpectedExternalID != "" { - assert.Equal(t, tc.ExpectedExternalID, status.ExternalID()) - } - if tc.ExpectedMsgID != 0 { - assert.Equal(t, tc.ExpectedMsgID, int64(status.ID())) - } - } else { - assert.Empty(t, mb.WrittenMsgStatuses(), "unexpected msg status written") - } - - if tc.ExpectedEvent != "" { - require.Len(mb.WrittenChannelEvents(), 1, "expected a channel event to be written") - event := mb.WrittenChannelEvents()[0] - - assert.Equal(t, tc.ExpectedEvent, event.EventType()) - assert.Equal(t, tc.ExpectedEventExtra, event.Extra()) - assert.Equal(t, tc.ExpectedURN, event.URN()) - - if !tc.ExpectedDate.IsZero() { - assert.Equal(t, tc.ExpectedDate, event.OccurredOn()) - } - } else { - assert.Empty(t, mb.WrittenChannelEvents(), "unexpected channel event written") - } - - if tc.ExpectedContactName != nil { - require.Equal(*tc.ExpectedContactName, mb.LastContactName()) - } - - // if we're expecting a message, status or event, check we have a log for it - if tc.ExpectedMsgText != nil || tc.ExpectedMsgStatus != "" || tc.ExpectedEvent != "" { - assert.Greater(t, len(mb.WrittenChannelLogs()), 0, "expected at least one channel log") - } - }) - } - - // check non-channel specific error conditions against first test case - validCase := testCases[0] - - if !validCase.NoQueueErrorCheck { - t.Run("Queue Error", func(t *testing.T) { - mb.SetErrorOnQueue(true) - defer mb.SetErrorOnQueue(false) - testHandlerRequest(t, s, validCase.URL, validCase.Headers, validCase.Data, validCase.MultipartForm, 400, Sp("unable to queue message"), validCase.PrepRequest) - }) - } - - if !validCase.NoInvalidChannelCheck { - t.Run("Receive With Invalid Channel", func(t *testing.T) { - mb.ClearChannels() - testHandlerRequest(t, s, validCase.URL, validCase.Headers, validCase.Data, validCase.MultipartForm, 400, Sp("channel not found"), validCase.PrepRequest) - }) - } } // RunChannelBenchmarks runs all the passed in test cases for the passed in channels @@ -453,7 +449,7 @@ func RunChannelBenchmarks(b *testing.B, channels []courier.Channel, handler cour b.Run(testCase.Label, func(b *testing.B) { for i := 0; i < b.N; i++ { - testHandlerRequest(b, s, testCase.URL, testCase.Headers, testCase.Data, testCase.MultipartForm, testCase.ExpectedRespStatus, nil, testCase.PrepRequest) + testHandlerRequest(b, s, testCase.URL, testCase.Headers, testCase.Data, testCase.MultipartForm, testCase.ExpectedRespStatus, "", testCase.PrepRequest) } }) } @@ -476,3 +472,6 @@ func AssertChannelLogRedaction(t *testing.T, clog *courier.ChannelLog, vals []st assertRedacted(e.Message()) } } + +// Sp is a utility method to get the pointer to the passed in string +func Sp(s string) *string { return &s } From 69f3b5452a470e2be13219084c6d947dfd0926ab Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 15 Sep 2022 10:21:17 -0500 Subject: [PATCH 168/294] Rename handler test field for clarity --- .../africastalking/africastalking_test.go | 120 +-- handlers/arabiacell/arabiacell_test.go | 24 +- handlers/blackmyna/blackmyna_test.go | 62 +- handlers/bongolive/bongolive_test.go | 80 +- handlers/burstsms/burstsms_test.go | 40 +- handlers/chikka/chikka_test.go | 92 +- handlers/clickatell/clickatell_test.go | 178 ++-- handlers/clickmobile/clickmobile_test.go | 102 +-- handlers/clicksend/clicksend_test.go | 28 +- handlers/dart/dart_test.go | 86 +- handlers/discord/discord_test.go | 42 +- handlers/dmark/dmark_test.go | 88 +- handlers/external/external_test.go | 340 +++---- handlers/facebook/facebook_test.go | 328 +++---- handlers/facebookapp/facebookapp_test.go | 866 +++++++++--------- handlers/firebase/firebase_test.go | 60 +- handlers/freshchat/freshchat_test.go | 60 +- handlers/globe/globe_test.go | 66 +- .../highconnection/highconnection_test.go | 80 +- handlers/hormuud/hormuud_test.go | 52 +- handlers/i2sms/i2sms_test.go | 24 +- handlers/infobip/infobip_test.go | 138 +-- handlers/jasmin/jasmin_test.go | 84 +- handlers/jiochat/jiochat_test.go | 52 +- handlers/junebug/junebug_test.go | 30 +- handlers/kaleyra/kaleyra_test.go | 104 +-- handlers/kannel/kannel_test.go | 24 +- handlers/line/line_test.go | 22 +- handlers/m3tech/m3tech_test.go | 34 +- handlers/macrokiosk/macrokiosk_test.go | 20 +- handlers/mblox/mblox_test.go | 12 +- handlers/messangi/messangi_test.go | 24 +- handlers/mtarget/mtarget_test.go | 18 +- handlers/nexmo/nexmo_test.go | 118 +-- handlers/novo/novo_test.go | 38 +- handlers/playmobile/playmobile_test.go | 68 +- handlers/plivo/plivo_test.go | 16 +- handlers/rocketchat/rocketchat_test.go | 32 +- handlers/shaqodoon/shaqodoon_test.go | 18 +- handlers/slack/slack_test.go | 82 +- handlers/smscentral/smscentral_test.go | 58 +- handlers/start/start_test.go | 110 +-- handlers/telegram/telegram_test.go | 282 +++--- handlers/telesom/telesom_test.go | 80 +- handlers/test.go | 36 +- handlers/thinq/thinq_test.go | 90 +- handlers/twiml/twiml_test.go | 128 +-- handlers/twitter/twitter_test.go | 14 +- handlers/viber/viber_test.go | 76 +- handlers/vk/vk_test.go | 190 ++-- handlers/wavy/wavy_test.go | 122 +-- handlers/wechat/wechat_test.go | 50 +- handlers/whatsapp/whatsapp_test.go | 36 +- handlers/yo/yo_test.go | 16 +- handlers/zenvia/zenvia_test.go | 44 +- handlers/zenviaold/zenviaold_test.go | 26 +- 56 files changed, 2555 insertions(+), 2555 deletions(-) diff --git a/handlers/africastalking/africastalking_test.go b/handlers/africastalking/africastalking_test.go index f58cfdc1d..744afb996 100644 --- a/handlers/africastalking/africastalking_test.go +++ b/handlers/africastalking/africastalking_test.go @@ -21,84 +21,84 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=%2B254791541111", - ExpectedRespStatus: 200, - ExpectedRespBody: "Message Accepted", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+254791541111", - ExpectedExternalID: "ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3", - ExpectedDate: time.Date(2017, 5, 3, 06, 04, 45, 0, time.UTC), + Label: "Receive Valid", + URL: receiveURL, + Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=%2B254791541111", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+254791541111", + ExpectedExternalID: "ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3", + ExpectedDate: time.Date(2017, 5, 3, 06, 04, 45, 0, time.UTC), }, { - Label: "Receive Valid", - URL: receiveURL, - Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03+06%3A04%3A45&from=%2B254791541111", - ExpectedRespStatus: 200, - ExpectedRespBody: "Message Accepted", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+254791541111", - ExpectedExternalID: "ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3", - ExpectedDate: time.Date(2017, 5, 3, 06, 04, 45, 0, time.UTC), + Label: "Receive Valid", + URL: receiveURL, + Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03+06%3A04%3A45&from=%2B254791541111", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+254791541111", + ExpectedExternalID: "ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3", + ExpectedDate: time.Date(2017, 5, 3, 06, 04, 45, 0, time.UTC), }, { - Label: "Receive Empty", - URL: receiveURL, - Data: "empty", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'id' required", + Label: "Receive Empty", + URL: receiveURL, + Data: "empty", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'id' required", }, { - Label: "Receive Missing Text", - URL: receiveURL, - Data: "linkId=03090445075804249226&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=%2B254791541111", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'text' required", + Label: "Receive Missing Text", + URL: receiveURL, + Data: "linkId=03090445075804249226&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=%2B254791541111", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'text' required", }, { - Label: "Invalid URN", - URL: receiveURL, - Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=MTN", - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL, + Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04%3A45Z&from=MTN", + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, { - Label: "Invalid Date", - URL: receiveURL, - Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04&from=%2B254791541111", - ExpectedRespStatus: 400, - ExpectedRespBody: "invalid date format", + Label: "Invalid Date", + URL: receiveURL, + Data: "linkId=03090445075804249226&text=Msg&to=21512&id=ec9adc86-51d5-4bc8-8eb0-d8ab0bb53dc3&date=2017-05-03T06%3A04&from=%2B254791541111", + ExpectedRespStatus: 400, + ExpectedBodyContains: "invalid date format", }, { - Label: "Status Invalid", - URL: statusURL, - Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Borked", - ExpectedRespStatus: 400, - ExpectedRespBody: "unknown status", + Label: "Status Invalid", + URL: statusURL, + Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Borked", + ExpectedRespStatus: 400, + ExpectedBodyContains: "unknown status", }, { - Label: "Status Missing", - URL: statusURL, - Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'status' required", + Label: "Status Missing", + URL: statusURL, + Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'status' required", }, { - Label: "Status Success", - URL: statusURL, - Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Success", - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"D"`, - ExpectedMsgStatus: courier.MsgDelivered, + Label: "Status Success", + URL: statusURL, + Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Success", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, }, { - Label: "Status Expired", - URL: statusURL, - Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Expired", - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"F"`, - ExpectedMsgStatus: courier.MsgFailed, + Label: "Status Expired", + URL: statusURL, + Data: "id=ATXid_dda018a640edfcc5d2ce455de3e4a6e7&status=Expired", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, }, } diff --git a/handlers/arabiacell/arabiacell_test.go b/handlers/arabiacell/arabiacell_test.go index 40d7cd5d0..788095c0b 100644 --- a/handlers/arabiacell/arabiacell_test.go +++ b/handlers/arabiacell/arabiacell_test.go @@ -19,20 +19,20 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: "B=Msg&M=254791541111", - ExpectedRespStatus: 200, - ExpectedRespBody: "Message Accepted", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+254791541111", + Label: "Receive Valid", + URL: receiveURL, + Data: "B=Msg&M=254791541111", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+254791541111", }, { - Label: "Receive Missing Number", - URL: receiveURL, - Data: "B=Msg", - ExpectedRespStatus: 400, - ExpectedRespBody: "required field 'M'", + Label: "Receive Missing Number", + URL: receiveURL, + Data: "B=Msg", + ExpectedRespStatus: 400, + ExpectedBodyContains: "required field 'M'", }, } diff --git a/handlers/blackmyna/blackmyna_test.go b/handlers/blackmyna/blackmyna_test.go index 24360095b..5730f74d0 100644 --- a/handlers/blackmyna/blackmyna_test.go +++ b/handlers/blackmyna/blackmyna_test.go @@ -21,49 +21,49 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL + "?to=3344&smsc=ncell&from=%2B9779814641111&text=Msg", - ExpectedRespStatus: 200, - ExpectedRespBody: "Message Accepted", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+9779814641111", + Label: "Receive Valid", + URL: receiveURL + "?to=3344&smsc=ncell&from=%2B9779814641111&text=Msg", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+9779814641111", }, { - Label: "Invalid URN", - URL: receiveURL + "?to=3344&smsc=ncell&from=MTN&text=Msg", - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL + "?to=3344&smsc=ncell&from=MTN&text=Msg", + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, { - Label: "Receive Empty", - URL: receiveURL + "", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'text' required", + Label: "Receive Empty", + URL: receiveURL + "", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'text' required", }, { - Label: "Receive Missing Text", - URL: receiveURL + "?to=3344&smsc=ncell&from=%2B9779814641111", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'text' required", + Label: "Receive Missing Text", + URL: receiveURL + "?to=3344&smsc=ncell&from=%2B9779814641111", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'text' required", }, { - Label: "Status Invalid", - URL: statusURL + "?id=bmID&status=13", - ExpectedRespStatus: 400, - ExpectedRespBody: "unknown status", + Label: "Status Invalid", + URL: statusURL + "?id=bmID&status=13", + ExpectedRespStatus: 400, + ExpectedBodyContains: "unknown status", }, { - Label: "Status Missing", - URL: statusURL + "?", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'status' required", + Label: "Status Missing", + URL: statusURL + "?", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'status' required", }, { - Label: "Valid Status", - URL: statusURL + "?id=bmID&status=2", - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"F"`, - ExpectedMsgStatus: courier.MsgFailed, + Label: "Valid Status", + URL: statusURL + "?id=bmID&status=2", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, }, } diff --git a/handlers/bongolive/bongolive_test.go b/handlers/bongolive/bongolive_test.go index 03842bbf3..251608aad 100644 --- a/handlers/bongolive/bongolive_test.go +++ b/handlers/bongolive/bongolive_test.go @@ -19,58 +19,58 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: "msgtype=1&id=12345678&message=Msg&sourceaddr=254791541111", - ExpectedRespStatus: 200, - ExpectedRespBody: "", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+254791541111", + Label: "Receive Valid", + URL: receiveURL, + Data: "msgtype=1&id=12345678&message=Msg&sourceaddr=254791541111", + ExpectedRespStatus: 200, + ExpectedBodyContains: "", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+254791541111", }, { - Label: "Receive Valid", - URL: receiveURL, - Data: "id=12345678&message=Msg&sourceaddr=254791541111", - ExpectedRespStatus: 200, - ExpectedRespBody: "", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+254791541111", + Label: "Receive Valid", + URL: receiveURL, + Data: "id=12345678&message=Msg&sourceaddr=254791541111", + ExpectedRespStatus: 200, + ExpectedBodyContains: "", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+254791541111", }, { - Label: "Receive Missing Number", - URL: receiveURL, - Data: "msgtype=1&id=12345679&message=Msg", - ExpectedRespStatus: 400, - ExpectedRespBody: "", + Label: "Receive Missing Number", + URL: receiveURL, + Data: "msgtype=1&id=12345679&message=Msg", + ExpectedRespStatus: 400, + ExpectedBodyContains: "", }, { - Label: "Status No params", - URL: receiveURL, - Data: "", - ExpectedRespStatus: 405, - ExpectedRespBody: "", + Label: "Status No params", + URL: receiveURL, + Data: "", + ExpectedRespStatus: 405, + ExpectedBodyContains: "", }, { - Label: "Status invalid params", - URL: receiveURL, - Data: "msgtype=5&dlrid=12345&status=12", - ExpectedRespStatus: 400, - ExpectedRespBody: "", + Label: "Status invalid params", + URL: receiveURL, + Data: "msgtype=5&dlrid=12345&status=12", + ExpectedRespStatus: 400, + ExpectedBodyContains: "", }, { - Label: "Status valid", - URL: receiveURL, - Data: "msgtype=5&dlrid=12345&status=1", - ExpectedRespStatus: 200, - ExpectedRespBody: "", - ExpectedMsgStatus: courier.MsgDelivered, + Label: "Status valid", + URL: receiveURL, + Data: "msgtype=5&dlrid=12345&status=1", + ExpectedRespStatus: 200, + ExpectedBodyContains: "", + ExpectedMsgStatus: courier.MsgDelivered, }, { - Label: "Invalid Msg Type", - URL: receiveURL, - Data: "msgtype=3&id=12345&status=1", - ExpectedRespStatus: 400, - ExpectedRespBody: "", + Label: "Invalid Msg Type", + URL: receiveURL, + Data: "msgtype=3&id=12345&status=1", + ExpectedRespStatus: 400, + ExpectedBodyContains: "", }, } diff --git a/handlers/burstsms/burstsms_test.go b/handlers/burstsms/burstsms_test.go index 64f5f8a42..e41a887a6 100644 --- a/handlers/burstsms/burstsms_test.go +++ b/handlers/burstsms/burstsms_test.go @@ -21,32 +21,32 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL + "?response=Msg&mobile=254791541111", - ExpectedRespStatus: 200, - ExpectedRespBody: "Message Accepted", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+254791541111", + Label: "Receive Valid", + URL: receiveURL + "?response=Msg&mobile=254791541111", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+254791541111", }, { - Label: "Receive Missing Number", - URL: receiveURL + "?response=Msg", - ExpectedRespStatus: 400, - ExpectedRespBody: "required field 'mobile'", + Label: "Receive Missing Number", + URL: receiveURL + "?response=Msg", + ExpectedRespStatus: 400, + ExpectedBodyContains: "required field 'mobile'", }, { - Label: "Status Valid", - URL: statusURL + "?message_id=12345&status=pending", - ExpectedRespStatus: 200, - ExpectedRespBody: "Status Update Accepted", - ExpectedExternalID: "12345", - ExpectedMsgStatus: "S", + Label: "Status Valid", + URL: statusURL + "?message_id=12345&status=pending", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Status Update Accepted", + ExpectedExternalID: "12345", + ExpectedMsgStatus: "S", }, { - Label: "Receive Invalid Status", - URL: statusURL + "?message_id=12345&status=unknown", - ExpectedRespStatus: 400, - ExpectedRespBody: "unknown status value", + Label: "Receive Invalid Status", + URL: statusURL + "?message_id=12345&status=unknown", + ExpectedRespStatus: 400, + ExpectedBodyContains: "unknown status value", }, } diff --git a/handlers/chikka/chikka_test.go b/handlers/chikka/chikka_test.go index 3b60b8772..55ceb3f31 100644 --- a/handlers/chikka/chikka_test.go +++ b/handlers/chikka/chikka_test.go @@ -20,66 +20,66 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: "message_type=incoming&mobile_number=639178020779&request_id=4004&message=Hello+World×tamp=1457670059.69", - ExpectedRespStatus: 200, - ExpectedRespBody: "Message Accepted", - ExpectedMsgText: Sp("Hello World"), - ExpectedURN: "tel:+639178020779", - ExpectedExternalID: "4004", - ExpectedDate: time.Date(2016, 03, 11, 04, 20, 59, 690000128, time.UTC), + Label: "Receive Valid", + URL: receiveURL, + Data: "message_type=incoming&mobile_number=639178020779&request_id=4004&message=Hello+World×tamp=1457670059.69", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Message Accepted", + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: "tel:+639178020779", + ExpectedExternalID: "4004", + ExpectedDate: time.Date(2016, 03, 11, 04, 20, 59, 690000128, time.UTC), }, { - Label: "Invalid URN", - URL: receiveURL, - Data: "message_type=incoming&mobile_number=MTN&request_id=4004&message=Hello+World×tamp=1457670059.69", - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL, + Data: "message_type=incoming&mobile_number=MTN&request_id=4004&message=Hello+World×tamp=1457670059.69", + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, { - Label: "Receive Mising Params", - URL: receiveURL, - Data: "message_type=incoming&message=Hello+World×tamp=1457670059.69", - ExpectedRespStatus: 400, - ExpectedRespBody: "Field validation for 'RequestID' failed", + Label: "Receive Mising Params", + URL: receiveURL, + Data: "message_type=incoming&message=Hello+World×tamp=1457670059.69", + ExpectedRespStatus: 400, + ExpectedBodyContains: "Field validation for 'RequestID' failed", }, { - Label: "Ignore Invalid message_type", - URL: receiveURL, - Data: "message_type=invalid", - ExpectedRespStatus: 200, - ExpectedRespBody: "unknown message_type request", + Label: "Ignore Invalid message_type", + URL: receiveURL, + Data: "message_type=invalid", + ExpectedRespStatus: 200, + ExpectedBodyContains: "unknown message_type request", }, { - Label: "Status Sent Valid", - URL: receiveURL, - Data: "message_type=outgoing&message_id=10&status=SENT", - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"S"`, - ExpectedMsgStatus: courier.MsgSent, + Label: "Status Sent Valid", + URL: receiveURL, + Data: "message_type=outgoing&message_id=10&status=SENT", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, }, { - Label: "Status Failed Valid", - URL: receiveURL, - Data: "message_type=outgoing&message_id=10&status=FAILED", - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"F"`, - ExpectedMsgStatus: courier.MsgFailed, + Label: "Status Failed Valid", + URL: receiveURL, + Data: "message_type=outgoing&message_id=10&status=FAILED", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, }, { - Label: "Status Invalid", - URL: receiveURL, - Data: "message_type=outgoing&message_id=10&status=UNKNOWN", - ExpectedRespStatus: 400, - ExpectedRespBody: `must be either 'SENT' or 'FAILED'`, + Label: "Status Invalid", + URL: receiveURL, + Data: "message_type=outgoing&message_id=10&status=UNKNOWN", + ExpectedRespStatus: 400, + ExpectedBodyContains: `must be either 'SENT' or 'FAILED'`, }, { - Label: "Status Missing Params", - URL: receiveURL, - Data: "message_type=outgoing", - ExpectedRespStatus: 400, - ExpectedRespBody: `Field validation for 'Status' failed `, + Label: "Status Missing Params", + URL: receiveURL, + Data: "message_type=outgoing", + ExpectedRespStatus: 400, + ExpectedBodyContains: `Field validation for 'Status' failed `, }, } diff --git a/handlers/clickatell/clickatell_test.go b/handlers/clickatell/clickatell_test.go index 43784a5d1..c9f650ed9 100644 --- a/handlers/clickatell/clickatell_test.go +++ b/handlers/clickatell/clickatell_test.go @@ -132,95 +132,95 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Valid Receive", - URL: receiveURL, - Data: receiveValidMessage, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Hello World!"), - ExpectedURN: "tel:+250788383383", - ExpectedExternalID: "1234", - ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC), - }, - { - Label: "Valid Receive ISO-8859-1", - URL: receiveURL, - Data: receiveValidMessageISO8859_1, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp(`hello!`), - ExpectedURN: "tel:+250788383383", - ExpectedExternalID: "1234", - ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC), - }, - { - Label: "Invalid URN", - URL: receiveURL, - Data: invalidURN, - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", - }, - { - Label: "Error invalid JSON", - URL: receiveURL, - Data: "foo", - ExpectedRespStatus: 400, - ExpectedRespBody: `unable to parse request JSON`, - }, - { - Label: "Error missing JSON", - URL: receiveURL, - Data: "{}", - ExpectedRespStatus: 400, - ExpectedRespBody: `missing one of 'messageId`, - }, - { - Label: "Valid Receive UTF-16BE", - URL: receiveURL, - Data: receiveValidMessageUTF16BE, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("mexico k mis papas no tenýa dinero para comprarnos lo q querýamos.."), - ExpectedURN: "tel:+250788383383", - ExpectedExternalID: "1234", - ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC), - }, - { - Label: "Valid Failed status report", - URL: statusURL, - Data: `{"messageId": "msg1", "statusCode": 5}`, - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"F"`, - ExpectedMsgStatus: courier.MsgFailed, - }, - { - Label: "Valid Delivered status report", - URL: statusURL, - Data: `{"messageId": "msg1", "statusCode": 4}`, - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"S"`, - ExpectedMsgStatus: courier.MsgSent, - }, - { - Label: "Unexpected status report", - URL: statusURL, - Data: `{"messageId": "msg1", "statusCode": -1}`, - ExpectedRespStatus: 400, - ExpectedRespBody: `unknown status '-1', must be one`, - }, - { - Label: "Invalid status report", - URL: statusURL, - Data: "{}", - ExpectedRespStatus: 400, - ExpectedRespBody: `missing one of 'messageId'`, - }, - { - Label: "Invalid JSON", - URL: statusURL, - Data: "foo", - ExpectedRespStatus: 400, - ExpectedRespBody: `unable to parse request JSON`, + Label: "Valid Receive", + URL: receiveURL, + Data: receiveValidMessage, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Hello World!"), + ExpectedURN: "tel:+250788383383", + ExpectedExternalID: "1234", + ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC), + }, + { + Label: "Valid Receive ISO-8859-1", + URL: receiveURL, + Data: receiveValidMessageISO8859_1, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp(`hello!`), + ExpectedURN: "tel:+250788383383", + ExpectedExternalID: "1234", + ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC), + }, + { + Label: "Invalid URN", + URL: receiveURL, + Data: invalidURN, + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", + }, + { + Label: "Error invalid JSON", + URL: receiveURL, + Data: "foo", + ExpectedRespStatus: 400, + ExpectedBodyContains: `unable to parse request JSON`, + }, + { + Label: "Error missing JSON", + URL: receiveURL, + Data: "{}", + ExpectedRespStatus: 400, + ExpectedBodyContains: `missing one of 'messageId`, + }, + { + Label: "Valid Receive UTF-16BE", + URL: receiveURL, + Data: receiveValidMessageUTF16BE, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("mexico k mis papas no tenýa dinero para comprarnos lo q querýamos.."), + ExpectedURN: "tel:+250788383383", + ExpectedExternalID: "1234", + ExpectedDate: time.Date(2018, 1, 17, 19, 35, 11, 0, time.UTC), + }, + { + Label: "Valid Failed status report", + URL: statusURL, + Data: `{"messageId": "msg1", "statusCode": 5}`, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, + }, + { + Label: "Valid Delivered status report", + URL: statusURL, + Data: `{"messageId": "msg1", "statusCode": 4}`, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, + }, + { + Label: "Unexpected status report", + URL: statusURL, + Data: `{"messageId": "msg1", "statusCode": -1}`, + ExpectedRespStatus: 400, + ExpectedBodyContains: `unknown status '-1', must be one`, + }, + { + Label: "Invalid status report", + URL: statusURL, + Data: "{}", + ExpectedRespStatus: 400, + ExpectedBodyContains: `missing one of 'messageId'`, + }, + { + Label: "Invalid JSON", + URL: statusURL, + Data: "foo", + ExpectedRespStatus: 400, + ExpectedBodyContains: `unable to parse request JSON`, }, } diff --git a/handlers/clickmobile/clickmobile_test.go b/handlers/clickmobile/clickmobile_test.go index cd86d2cdf..cff119ff4 100644 --- a/handlers/clickmobile/clickmobile_test.go +++ b/handlers/clickmobile/clickmobile_test.go @@ -66,71 +66,71 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: receiveURL, - Data: validReceive, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+265990099333", - ExpectedExternalID: "1232434354", + Label: "Receive Valid Message", + URL: receiveURL, + Data: validReceive, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+265990099333", + ExpectedExternalID: "1232434354", }, { - Label: "Invalid URN", - URL: receiveURL, - Data: invalidURNReceive, - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL, + Data: invalidURNReceive, + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, { - Label: "Receive valid with empty text", - URL: receiveURL, - Data: validReceiveEmptyText, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp(""), - ExpectedURN: "tel:+265990099333", - ExpectedExternalID: "1232434354", + Label: "Receive valid with empty text", + URL: receiveURL, + Data: validReceiveEmptyText, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedURN: "tel:+265990099333", + ExpectedExternalID: "1232434354", }, { - Label: "Receive valid missing text", - URL: receiveURL, - Data: validMissingText, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp(""), - ExpectedURN: "tel:+265990099333", - ExpectedExternalID: "1232434354", + Label: "Receive valid missing text", + URL: receiveURL, + Data: validMissingText, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedURN: "tel:+265990099333", + ExpectedExternalID: "1232434354", }, { - Label: "Receive valid missing referenceID", - URL: receiveURL, - Data: validMissingReferenceID, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+265990099333", + Label: "Receive valid missing referenceID", + URL: receiveURL, + Data: validMissingReferenceID, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+265990099333", }, { - Label: "Missing Shortcode", - URL: receiveURL, - Data: missingShortcode, - ExpectedRespStatus: 400, - ExpectedRespBody: "missing parameters, must have 'mobile' and 'shortcode'", + Label: "Missing Shortcode", + URL: receiveURL, + Data: missingShortcode, + ExpectedRespStatus: 400, + ExpectedBodyContains: "missing parameters, must have 'mobile' and 'shortcode'", }, { - Label: "Missing Mobile", - URL: receiveURL, - Data: missingMobile, - ExpectedRespStatus: 400, - ExpectedRespBody: "missing parameters, must have 'mobile' and 'shortcode'", + Label: "Missing Mobile", + URL: receiveURL, + Data: missingMobile, + ExpectedRespStatus: 400, + ExpectedBodyContains: "missing parameters, must have 'mobile' and 'shortcode'", }, { - Label: "Receive invalid XML", - URL: receiveURL, - Data: "empty", - ExpectedRespStatus: 400, - ExpectedRespBody: "unable to parse request XML", + Label: "Receive invalid XML", + URL: receiveURL, + Data: "empty", + ExpectedRespStatus: 400, + ExpectedBodyContains: "unable to parse request XML", }, } diff --git a/handlers/clicksend/clicksend_test.go b/handlers/clicksend/clicksend_test.go index 376cd2eed..29743a0b3 100644 --- a/handlers/clicksend/clicksend_test.go +++ b/handlers/clicksend/clicksend_test.go @@ -20,22 +20,22 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: receiveURL, - Data: `from=639171234567&body=hello+world`, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("hello world"), - ExpectedURN: "tel:+639171234567", + Label: "Receive Valid Message", + URL: receiveURL, + Data: `from=639171234567&body=hello+world`, + Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("hello world"), + ExpectedURN: "tel:+639171234567", }, { - Label: "Receive Missing From", - URL: receiveURL, - Data: `body=hello+world`, - Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - ExpectedRespStatus: 400, - ExpectedRespBody: "Error", + Label: "Receive Missing From", + URL: receiveURL, + Data: `body=hello+world`, + Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + ExpectedRespStatus: 400, + ExpectedBodyContains: "Error", }, } diff --git a/handlers/dart/dart_test.go b/handlers/dart/dart_test.go index d4f79030f..8aabf2d9a 100644 --- a/handlers/dart/dart_test.go +++ b/handlers/dart/dart_test.go @@ -20,66 +20,66 @@ const ( var daTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL + "?userid=testusr&password=test&original=6289881134560&sendto=2020&message=Msg", - ExpectedRespStatus: 200, - ExpectedRespBody: "000", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+6289881134560", + Label: "Receive Valid", + URL: receiveURL + "?userid=testusr&password=test&original=6289881134560&sendto=2020&message=Msg", + ExpectedRespStatus: 200, + ExpectedBodyContains: "000", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+6289881134560", }, { - Label: "Receive Valid", - URL: receiveURL + "?userid=testusr&password=test&original=cmp-oodddqddwdwdcd&sendto=2020&message=Msg", - ExpectedRespStatus: 200, - ExpectedRespBody: "000", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "ext:cmp-oodddqddwdwdcd", + Label: "Receive Valid", + URL: receiveURL + "?userid=testusr&password=test&original=cmp-oodddqddwdwdcd&sendto=2020&message=Msg", + ExpectedRespStatus: 200, + ExpectedBodyContains: "000", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "ext:cmp-oodddqddwdwdcd", }, { - Label: "Receive Invalid", - URL: receiveURL, - ExpectedRespStatus: 400, - ExpectedRespBody: "missing required parameters original and sendto", + Label: "Receive Invalid", + URL: receiveURL, + ExpectedRespStatus: 400, + ExpectedBodyContains: "missing required parameters original and sendto", }, { - Label: "Valid Status", - URL: statusURL + "?status=10&messageid=12345", - ExpectedRespStatus: 200, - ExpectedRespBody: "000", - ExpectedMsgStatus: "D", + Label: "Valid Status", + URL: statusURL + "?status=10&messageid=12345", + ExpectedRespStatus: 200, + ExpectedBodyContains: "000", + ExpectedMsgStatus: "D", }, { - Label: "Valid Status", - URL: statusURL + "?status=10&messageid=12345.2", - ExpectedRespStatus: 200, - ExpectedRespBody: "000", - ExpectedMsgStatus: "D", + Label: "Valid Status", + URL: statusURL + "?status=10&messageid=12345.2", + ExpectedRespStatus: 200, + ExpectedBodyContains: "000", + ExpectedMsgStatus: "D", }, { - Label: "Failed Status", - URL: statusURL + "?status=30&messageid=12345", - ExpectedRespStatus: 200, - ExpectedRespBody: "000", - ExpectedMsgStatus: "F", + Label: "Failed Status", + URL: statusURL + "?status=30&messageid=12345", + ExpectedRespStatus: 200, + ExpectedBodyContains: "000", + ExpectedMsgStatus: "F", }, { - Label: "Missing Status", - URL: statusURL + "?messageid=12345", - ExpectedRespStatus: 400, - ExpectedRespBody: "parameters messageid and status should not be empty", + Label: "Missing Status", + URL: statusURL + "?messageid=12345", + ExpectedRespStatus: 400, + ExpectedBodyContains: "parameters messageid and status should not be empty", }, { - Label: "Missing Status", - URL: statusURL + "?status=foo&messageid=12345", - ExpectedRespStatus: 400, - ExpectedRespBody: "parsing failed: status 'foo' is not an integer", + Label: "Missing Status", + URL: statusURL + "?status=foo&messageid=12345", + ExpectedRespStatus: 400, + ExpectedBodyContains: "parsing failed: status 'foo' is not an integer", }, { - Label: "Missing Status", - URL: statusURL + "?status=10&messageid=abc", - ExpectedRespStatus: 400, - ExpectedRespBody: "parsing failed: messageid 'abc' is not an integer", + Label: "Missing Status", + URL: statusURL + "?status=10&messageid=abc", + ExpectedRespStatus: 400, + ExpectedBodyContains: "parsing failed: messageid 'abc' is not an integer", }, } diff --git a/handlers/discord/discord_test.go b/handlers/discord/discord_test.go index 176b0180e..3ce02df0a 100644 --- a/handlers/discord/discord_test.go +++ b/handlers/discord/discord_test.go @@ -41,33 +41,33 @@ var testCases = []ChannelHandleTestCase{ ExpectedAttachments: []string{"https://test.test/foo.png"}, }, { - Label: "Invalid ID", - URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", - Data: `from=somebody&text=hello`, - ExpectedRespStatus: 400, - ExpectedRespBody: "Error", + Label: "Invalid ID", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", + Data: `from=somebody&text=hello`, + ExpectedRespStatus: 400, + ExpectedBodyContains: "Error", }, { - Label: "Garbage Body", - URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", - Data: `sdfaskdfajsdkfajsdfaksdf`, - ExpectedRespStatus: 400, - ExpectedRespBody: "Error", + Label: "Garbage Body", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", + Data: `sdfaskdfajsdkfajsdfaksdf`, + ExpectedRespStatus: 400, + ExpectedBodyContains: "Error", }, { - Label: "Missing Text", - URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", - Data: `from=694634743521607802`, - ExpectedRespStatus: 400, - ExpectedRespBody: "Error", + Label: "Missing Text", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/receive", + Data: `from=694634743521607802`, + ExpectedRespStatus: 400, + ExpectedBodyContains: "Error", }, { - Label: "Message Sent Handler", - URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/sent/", - Data: `id=12345`, - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"S"`, - ExpectedMsgStatus: courier.MsgSent, + Label: "Message Sent Handler", + URL: "/c/ds/bac782c2-7aeb-4389-92f5-97887744f573/sent/", + Data: `id=12345`, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, }, { Label: "Message Sent Handler Garbage", diff --git a/handlers/dmark/dmark_test.go b/handlers/dmark/dmark_test.go index ff6d6a2a7..801cf6eb9 100644 --- a/handlers/dmark/dmark_test.go +++ b/handlers/dmark/dmark_test.go @@ -21,64 +21,64 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: "text=Msg&short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=254791541111", - ExpectedRespStatus: 200, - ExpectedRespBody: "Message Accepted", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+254791541111", - ExpectedDate: time.Date(2017, 10, 26, 15, 51, 32, 906335000, time.UTC), + Label: "Receive Valid", + URL: receiveURL, + Data: "text=Msg&short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=254791541111", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+254791541111", + ExpectedDate: time.Date(2017, 10, 26, 15, 51, 32, 906335000, time.UTC), }, { - Label: "Invalid URN", - URL: receiveURL, - Data: "text=Msg&short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=MTN", - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL, + Data: "text=Msg&short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=MTN", + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, { - Label: "Receive Empty", - URL: receiveURL, - Data: "empty", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'msisdn' required", + Label: "Receive Empty", + URL: receiveURL, + Data: "empty", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'msisdn' required", }, { - Label: "Receive Missing Text", - URL: receiveURL, - Data: "short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=254791541111", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'text' required", + Label: "Receive Missing Text", + URL: receiveURL, + Data: "short_code=2020&tstamp=2017-10-26T15:51:32.906335%2B00:00&msisdn=254791541111", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'text' required", }, { - Label: "Receive Invalid TS", - URL: receiveURL, - Data: "text=Msg&short_code=2020&tstamp=2017-10-26&msisdn=254791541111", - ExpectedRespStatus: 400, - ExpectedRespBody: "invalid tstamp", + Label: "Receive Invalid TS", + URL: receiveURL, + Data: "text=Msg&short_code=2020&tstamp=2017-10-26&msisdn=254791541111", + ExpectedRespStatus: 400, + ExpectedBodyContains: "invalid tstamp", }, { - Label: "Status Invalid", - URL: statusURL, - Data: "id=12345&status=Borked", - ExpectedRespStatus: 400, - ExpectedRespBody: "unknown status", + Label: "Status Invalid", + URL: statusURL, + Data: "id=12345&status=Borked", + ExpectedRespStatus: 400, + ExpectedBodyContains: "unknown status", }, { - Label: "Status Missing", - URL: statusURL, - Data: "id=12345", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'status' required", + Label: "Status Missing", + URL: statusURL, + Data: "id=12345", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'status' required", }, { - Label: "Status Valid", - URL: statusURL, - Data: "id=12345&status=1", - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"D"`, - ExpectedMsgStatus: courier.MsgDelivered, + Label: "Status Valid", + URL: statusURL, + Data: "id=12345&status=1", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, }, } diff --git a/handlers/external/external_test.go b/handlers/external/external_test.go index f686c8951..17cdb7f4b 100644 --- a/handlers/external/external_test.go +++ b/handlers/external/external_test.go @@ -26,169 +26,169 @@ var gmChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: receiveURL + "?sender=%2B2349067554729&text=Join", - Data: "empty", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", - }, - { - Label: "Receive Valid Post", - URL: receiveURL, - Data: "sender=%2B2349067554729&text=Join", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", - }, - { - Label: "Receive Valid Post multipart form", - URL: receiveURL, - MultipartForm: map[string]string{"sender": "2349067554729", "text": "Join"}, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", - }, - { - Label: "Receive Valid From", - URL: receiveURL + "?from=%2B2349067554729&text=Join", - Data: "empty", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", - }, - { - Label: "Receive Country Parse", - URL: receiveURL + "?from=2349067554729&text=Join", - Data: "empty", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", - }, - { - Label: "Receive Valid Message With Date", - URL: receiveURL + "?sender=%2B2349067554729&text=Join&date=2017-06-23T12:30:00.500Z", - Data: "empty", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", - ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC), - }, - { - Label: "Receive Valid Message With Time", - URL: receiveURL + "?sender=%2B2349067554729&text=Join&time=2017-06-23T12:30:00Z", - Data: "empty", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", - ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC), - }, - { - Label: "Invalid URN", - URL: receiveURL + "?sender=MTN&text=Join", - Data: "empty", - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", - }, - { - Label: "Receive No Params", - URL: receiveURL, - Data: "empty", - ExpectedRespStatus: 400, - ExpectedRespBody: "must have one of 'sender' or 'from' set", + Label: "Receive Valid Message", + URL: receiveURL + "?sender=%2B2349067554729&text=Join", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + }, + { + Label: "Receive Valid Post", + URL: receiveURL, + Data: "sender=%2B2349067554729&text=Join", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + }, + { + Label: "Receive Valid Post multipart form", + URL: receiveURL, + MultipartForm: map[string]string{"sender": "2349067554729", "text": "Join"}, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + }, + { + Label: "Receive Valid From", + URL: receiveURL + "?from=%2B2349067554729&text=Join", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + }, + { + Label: "Receive Country Parse", + URL: receiveURL + "?from=2349067554729&text=Join", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + }, + { + Label: "Receive Valid Message With Date", + URL: receiveURL + "?sender=%2B2349067554729&text=Join&date=2017-06-23T12:30:00.500Z", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC), + }, + { + Label: "Receive Valid Message With Time", + URL: receiveURL + "?sender=%2B2349067554729&text=Join&time=2017-06-23T12:30:00Z", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC), + }, + { + Label: "Invalid URN", + URL: receiveURL + "?sender=MTN&text=Join", + Data: "empty", + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", + }, + { + Label: "Receive No Params", + URL: receiveURL, + Data: "empty", + ExpectedRespStatus: 400, + ExpectedBodyContains: "must have one of 'sender' or 'from' set", }, { Label: "Receive No Sender", URL: receiveURL + "?text=Join", Data: "empty", - ExpectedRespStatus: 400, ExpectedRespBody: "must have one of 'sender' or 'from' set", + ExpectedRespStatus: 400, ExpectedBodyContains: "must have one of 'sender' or 'from' set", }, { - Label: "Receive Invalid Date", - URL: receiveURL + "?sender=%2B2349067554729&text=Join&time=20170623T123000Z", - Data: "empty", - ExpectedRespStatus: 400, - ExpectedRespBody: "invalid date format, must be RFC 3339", + Label: "Receive Invalid Date", + URL: receiveURL + "?sender=%2B2349067554729&text=Join&time=20170623T123000Z", + Data: "empty", + ExpectedRespStatus: 400, + ExpectedBodyContains: "invalid date format, must be RFC 3339", }, { - Label: "Failed No Params", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/failed/", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'id' required", + Label: "Failed No Params", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/failed/", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'id' required", }, { - Label: "Failed Valid", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/failed/?id=12345", - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"F"`, - ExpectedMsgStatus: courier.MsgFailed, + Label: "Failed Valid", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/failed/?id=12345", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, }, { - Label: "Invalid Status", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/wired/", - ExpectedRespStatus: 404, - ExpectedRespBody: `page not found`, + Label: "Invalid Status", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/wired/", + ExpectedRespStatus: 404, + ExpectedBodyContains: `page not found`, }, { - Label: "Sent Valid", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/sent/?id=12345", - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"S"`, - ExpectedMsgStatus: courier.MsgSent, + Label: "Sent Valid", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/sent/?id=12345", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, }, { - Label: "Delivered Valid", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered/?id=12345", - Data: "nothing", - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"D"`, - ExpectedMsgStatus: courier.MsgDelivered, + Label: "Delivered Valid", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered/?id=12345", + Data: "nothing", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, }, { - Label: "Delivered Valid Post", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered/", - Data: "id=12345", - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"D"`, - ExpectedMsgStatus: courier.MsgDelivered, + Label: "Delivered Valid Post", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered/", + Data: "id=12345", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, }, { - Label: "Stopped Event", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/?from=%2B2349067554729", - Data: "nothing", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedEvent: "stop_contact", - ExpectedURN: "tel:+2349067554729", + Label: "Stopped Event", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/?from=%2B2349067554729", + Data: "nothing", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedEvent: "stop_contact", + ExpectedURN: "tel:+2349067554729", }, { - Label: "Stopped Event Post", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/", - Data: "from=%2B2349067554729", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedEvent: "stop_contact", - ExpectedURN: "tel:+2349067554729", + Label: "Stopped Event Post", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/", + Data: "from=%2B2349067554729", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedEvent: "stop_contact", + ExpectedURN: "tel:+2349067554729", }, { - Label: "Stopped Event Invalid URN", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/?from=MTN", - Data: "empty", - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Stopped Event Invalid URN", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/?from=MTN", + Data: "empty", + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, { - Label: "Stopped event No Params", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'from' required", + Label: "Stopped event No Params", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/stopped/", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'from' required", }, } @@ -205,32 +205,32 @@ var testSOAPReceiveChannels = []courier.Channel{ var handleSOAPReceiveTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Post SOAP", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", - Data: `2349067554729Join`, - ExpectedRespStatus: 200, - ExpectedRespBody: "0", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", + Label: "Receive Valid Post SOAP", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + Data: `2349067554729Join`, + ExpectedRespStatus: 200, + ExpectedBodyContains: "0", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", }, { - Label: "Receive Invalid SOAP", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", - Data: ``, - ExpectedRespStatus: 400, - ExpectedRespBody: "missing from", + Label: "Receive Invalid SOAP", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + Data: ``, + ExpectedRespStatus: 400, + ExpectedBodyContains: "missing from", }, } var gmTestCases = []ChannelHandleTestCase{ { - Label: "Receive Non Plus Message", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sender=2207222333&text=Join", - Data: "empty", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2207222333", + Label: "Receive Non Plus Message", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sender=2207222333&text=Join", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2207222333", }, } @@ -246,21 +246,21 @@ var customChannels = []courier.Channel{ var customTestCases = []ChannelHandleTestCase{ { - Label: "Receive Custom Message", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?from_number=12067799192&messageText=Join×tamp=2017-06-23T12:30:00Z", - Data: "empty", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+12067799192", - ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC), - }, - { - Label: "Receive Custom Missing", - URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sent_from=12067799192&messageText=Join", - Data: "empty", - ExpectedRespStatus: 400, - ExpectedRespBody: "must have one of 'sender' or 'from' set", + Label: "Receive Custom Message", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?from_number=12067799192&messageText=Join×tamp=2017-06-23T12:30:00Z", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+12067799192", + ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC), + }, + { + Label: "Receive Custom Missing", + URL: "/c/ex/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?sent_from=12067799192&messageText=Join", + Data: "empty", + ExpectedRespStatus: 400, + ExpectedBodyContains: "must have one of 'sender' or 'from' set", }, } diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index e6cb33e16..580035f72 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -419,192 +419,192 @@ var unkownMessagingEntry = `{ var testCases = []ChannelHandleTestCase{ { - Label: "Receive Message", - URL: receiveURL, - Data: helloMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedMsgText: Sp("Hello World"), - ExpectedURN: "facebook:5678", - ExpectedExternalID: "external_id", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + Label: "Receive Message", + URL: receiveURL, + Data: helloMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), }, { - Label: "No Duplicate Receive Message", - URL: receiveURL, - Data: duplicateMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedMsgText: Sp("Hello World"), - ExpectedURN: "facebook:5678", - ExpectedExternalID: "external_id", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + Label: "No Duplicate Receive Message", + URL: receiveURL, + Data: duplicateMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), }, { - Label: "Receive Attachment", - URL: receiveURL, - Data: attachment, - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedMsgText: Sp(""), - ExpectedAttachments: []string{"https://image-url/foo.png"}, - ExpectedURN: "facebook:5678", - ExpectedExternalID: "external_id", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + Label: "Receive Attachment", + URL: receiveURL, + Data: attachment, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"https://image-url/foo.png"}, + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), }, { - Label: "Receive Location", - URL: receiveURL, - Data: locationAttachment, - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedMsgText: Sp(""), - ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, - ExpectedURN: "facebook:5678", - ExpectedExternalID: "external_id", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + Label: "Receive Location", + URL: receiveURL, + Data: locationAttachment, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), }, { - Label: "Receive Thumbs Up", - URL: receiveURL, - Data: thumbsUp, - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedMsgText: Sp("👍"), - ExpectedURN: "facebook:5678", - ExpectedExternalID: "external_id", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + Label: "Receive Thumbs Up", + URL: receiveURL, + Data: thumbsUp, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgText: Sp("👍"), + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), }, { - Label: "Receive OptIn UserRef", - URL: receiveURL, - Data: optInUserRef, - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedURN: "facebook:ref:optin_user_ref", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedEvent: courier.Referral, - ExpectedEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, + Label: "Receive OptIn UserRef", + URL: receiveURL, + Data: optInUserRef, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedURN: "facebook:ref:optin_user_ref", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, }, { - Label: "Receive OptIn", - URL: receiveURL, - Data: optIn, - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedEvent: courier.Referral, - ExpectedEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, + Label: "Receive OptIn", + URL: receiveURL, + Data: optIn, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, }, { - Label: "Receive Get Started", - URL: receiveURL, - Data: postbackGetStarted, - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedEvent: courier.NewConversation, - ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, + Label: "Receive Get Started", + URL: receiveURL, + Data: postbackGetStarted, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.NewConversation, + ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, }, { - Label: "Receive Referral Postback", - URL: receiveURL, - Data: postback, - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedEvent: courier.Referral, - ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, + Label: "Receive Referral Postback", + URL: receiveURL, + Data: postback, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, }, { - Label: "Receive Referral", - URL: receiveURL, - Data: postbackReferral, - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedEvent: courier.Referral, - ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, + Label: "Receive Referral", + URL: receiveURL, + Data: postbackReferral, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, }, { - Label: "Receive Referral", - URL: receiveURL, - Data: referral, - ExpectedRespStatus: 200, - ExpectedRespBody: `"referrer_id":"referral id"`, - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedEvent: courier.Referral, - ExpectedEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, + Label: "Receive Referral", + URL: receiveURL, + Data: referral, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"referrer_id":"referral id"`, + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, }, { - Label: "Receive DLR", - URL: receiveURL, - Data: dlr, - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedMsgStatus: courier.MsgDelivered, - ExpectedExternalID: "mid.1458668856218:ed81099e15d3f4f233", + Label: "Receive DLR", + URL: receiveURL, + Data: dlr, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgStatus: courier.MsgDelivered, + ExpectedExternalID: "mid.1458668856218:ed81099e15d3f4f233", }, { - Label: "Different Page", - URL: receiveURL, - Data: differentPage, - ExpectedRespStatus: 200, - ExpectedRespBody: `"data":[]`, + Label: "Different Page", + URL: receiveURL, + Data: differentPage, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"data":[]`, }, { - Label: "Echo", - URL: receiveURL, - Data: echo, - ExpectedRespStatus: 200, - ExpectedRespBody: `ignoring echo`, + Label: "Echo", + URL: receiveURL, + Data: echo, + ExpectedRespStatus: 200, + ExpectedBodyContains: `ignoring echo`, }, { - Label: "Not Page", - URL: receiveURL, - Data: notPage, - ExpectedRespStatus: 200, - ExpectedRespBody: "ignoring", + Label: "Not Page", + URL: receiveURL, + Data: notPage, + ExpectedRespStatus: 200, + ExpectedBodyContains: "ignoring", }, { - Label: "No Entries", - URL: receiveURL, - Data: noEntries, - ExpectedRespStatus: 200, - ExpectedRespBody: "ignoring", + Label: "No Entries", + URL: receiveURL, + Data: noEntries, + ExpectedRespStatus: 200, + ExpectedBodyContains: "ignoring", }, { - Label: "No Messaging Entries", - URL: receiveURL, - Data: noMessagingEntries, - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", + Label: "No Messaging Entries", + URL: receiveURL, + Data: noMessagingEntries, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", }, { - Label: "Unknown Messaging Entry", - URL: receiveURL, - Data: unkownMessagingEntry, - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", + Label: "Unknown Messaging Entry", + URL: receiveURL, + Data: unkownMessagingEntry, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", }, { - Label: "Not JSON", - URL: receiveURL, - Data: `blargh`, - ExpectedRespStatus: 400, - ExpectedRespBody: "Error", + Label: "Not JSON", + URL: receiveURL, + Data: `blargh`, + ExpectedRespStatus: 400, + ExpectedBodyContains: "Error", }, { - Label: "Invalid URN", - URL: receiveURL, - Data: invalidURN, - ExpectedRespStatus: 400, - ExpectedRespBody: "invalid facebook id", + Label: "Invalid URN", + URL: receiveURL, + Data: invalidURN, + ExpectedRespStatus: 400, + ExpectedBodyContains: "invalid facebook id", }, } @@ -701,28 +701,28 @@ func TestVerify(t *testing.T) { ExpectedURN: "facebook:5678", }, { - Label: "Verify No Mode", - URL: receiveURL, - ExpectedRespStatus: 400, - ExpectedRespBody: "unknown request", + Label: "Verify No Mode", + URL: receiveURL, + ExpectedRespStatus: 400, + ExpectedBodyContains: "unknown request", }, { - Label: "Verify No Secret", - URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe", - ExpectedRespStatus: 400, - ExpectedRespBody: "token does not match secret", + Label: "Verify No Secret", + URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe", + ExpectedRespStatus: 400, + ExpectedBodyContains: "token does not match secret", }, { - Label: "Invalid Secret", - URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe&hub.verify_token=blah", - ExpectedRespStatus: 400, - ExpectedRespBody: "token does not match secret", + Label: "Invalid Secret", + URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe&hub.verify_token=blah", + ExpectedRespStatus: 400, + ExpectedBodyContains: "token does not match secret", }, { - Label: "Valid Secret", - URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe&hub.verify_token=mysecret&hub.challenge=yarchallenge", - ExpectedRespStatus: 200, - ExpectedRespBody: "yarchallenge", + Label: "Valid Secret", + URL: "/c/fb/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?hub.mode=subscribe&hub.verify_token=mysecret&hub.challenge=yarchallenge", + ExpectedRespStatus: 200, + ExpectedBodyContains: "yarchallenge", }, }) diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index bce9e5512..9069667d9 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -36,7 +36,7 @@ var testCasesFBA = []ChannelHandleTestCase{ URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", + ExpectedBodyContains: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Hello World"), @@ -46,208 +46,208 @@ var testCasesFBA = []ChannelHandleTestCase{ PrepRequest: addValidSignature, }, { - Label: "Receive Invalid Signature", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "ignoring request, invalid request signature", - PrepRequest: addInvalidSignature, - }, - { - Label: "No Duplicate Receive Message", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/duplicateMsgFBA.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedMsgText: Sp("Hello World"), - ExpectedURN: "facebook:5678", - ExpectedExternalID: "external_id", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature, - }, - { - Label: "Receive Attachment", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/attachmentFBA.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedMsgText: Sp(""), - ExpectedAttachments: []string{"https://image-url/foo.png"}, - ExpectedURN: "facebook:5678", - ExpectedExternalID: "external_id", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature, - }, - { - Label: "Receive Location", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/locationAttachment.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedMsgText: Sp(""), - ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, - ExpectedURN: "facebook:5678", - ExpectedExternalID: "external_id", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature, - }, - { - Label: "Receive Thumbs Up", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/thumbsUp.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedMsgText: Sp("👍"), - ExpectedURN: "facebook:5678", - ExpectedExternalID: "external_id", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature, - }, - { - Label: "Receive OptIn UserRef", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/optInUserRef.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedURN: "facebook:ref:optin_user_ref", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedEvent: courier.Referral, - ExpectedEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, - PrepRequest: addValidSignature, - }, - { - Label: "Receive OptIn", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/optIn.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedEvent: courier.Referral, - ExpectedEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, - PrepRequest: addValidSignature, - }, - { - Label: "Receive Get Started", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/postbackGetStarted.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedEvent: courier.NewConversation, - ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, - PrepRequest: addValidSignature, - }, - { - Label: "Receive Referral Postback", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/postback.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedEvent: courier.Referral, - ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, - PrepRequest: addValidSignature, - }, - { - Label: "Receive Referral", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/postbackReferral.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedEvent: courier.Referral, - ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, - PrepRequest: addValidSignature, - }, - { - Label: "Receive Referral", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/referral.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: `"referrer_id":"referral id"`, - ExpectedURN: "facebook:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedEvent: courier.Referral, - ExpectedEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, - PrepRequest: addValidSignature, - }, - { - Label: "Receive DLR", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/dlr.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedMsgStatus: courier.MsgDelivered, - ExpectedExternalID: "mid.1458668856218:ed81099e15d3f4f233", - PrepRequest: addValidSignature, - }, - { - Label: "Different Page", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/differentPageFBA.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: `"data":[]`, - PrepRequest: addValidSignature, - }, - { - Label: "Echo", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/echoFBA.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: `ignoring echo`, - PrepRequest: addValidSignature, - }, - { - Label: "Not Page", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/notPage.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notpage", - PrepRequest: addValidSignature, - }, - { - Label: "No Entries", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/noEntriesFBA.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "no entries found", - PrepRequest: addValidSignature, - }, - { - Label: "No Messaging Entries", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/noMessagingEntriesFBA.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - PrepRequest: addValidSignature, - }, - { - Label: "Unknown Messaging Entry", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/unknownMessagingEntryFBA.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - PrepRequest: addValidSignature, - }, - { - Label: "Not JSON", - URL: "/c/fba/receive", - Data: "not JSON", - ExpectedRespStatus: 200, - ExpectedRespBody: "unable to parse request JSON", - PrepRequest: addValidSignature, - }, - { - Label: "Invalid URN", - URL: "/c/fba/receive", - Data: string(test.ReadFile("./testdata/fba/invalidURNFBA.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "ignoring request, invalid facebook id", - PrepRequest: addValidSignature, + Label: "Receive Invalid Signature", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "ignoring request, invalid request signature", + PrepRequest: addInvalidSignature, + }, + { + Label: "No Duplicate Receive Message", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/duplicateMsgFBA.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Attachment", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/attachmentFBA.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"https://image-url/foo.png"}, + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Location", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/locationAttachment.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Thumbs Up", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/thumbsUp.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgText: Sp("👍"), + ExpectedURN: "facebook:5678", + ExpectedExternalID: "external_id", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive OptIn UserRef", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/optInUserRef.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedURN: "facebook:ref:optin_user_ref", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, + PrepRequest: addValidSignature, + }, + { + Label: "Receive OptIn", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/optIn.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"referrer_id": "optin_ref"}, + PrepRequest: addValidSignature, + }, + { + Label: "Receive Get Started", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/postbackGetStarted.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.NewConversation, + ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started"}, + PrepRequest: addValidSignature, + }, + { + Label: "Receive Referral Postback", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/postback.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "postback payload", "referrer_id": "postback ref", "source": "postback source", "type": "postback type"}, + PrepRequest: addValidSignature, + }, + { + Label: "Receive Referral", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/postbackReferral.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"title": "postback title", "payload": "get_started", "referrer_id": "postback ref", "source": "postback source", "type": "postback type", "ad_id": "ad id"}, + PrepRequest: addValidSignature, + }, + { + Label: "Receive Referral", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/referral.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: `"referrer_id":"referral id"`, + ExpectedURN: "facebook:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.Referral, + ExpectedEventExtra: map[string]interface{}{"referrer_id": "referral id", "source": "referral source", "type": "referral type", "ad_id": "ad id"}, + PrepRequest: addValidSignature, + }, + { + Label: "Receive DLR", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/dlr.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgStatus: courier.MsgDelivered, + ExpectedExternalID: "mid.1458668856218:ed81099e15d3f4f233", + PrepRequest: addValidSignature, + }, + { + Label: "Different Page", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/differentPageFBA.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: `"data":[]`, + PrepRequest: addValidSignature, + }, + { + Label: "Echo", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/echoFBA.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: `ignoring echo`, + PrepRequest: addValidSignature, + }, + { + Label: "Not Page", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/notPage.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notpage", + PrepRequest: addValidSignature, + }, + { + Label: "No Entries", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/noEntriesFBA.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "no entries found", + PrepRequest: addValidSignature, + }, + { + Label: "No Messaging Entries", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/noMessagingEntriesFBA.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + PrepRequest: addValidSignature, + }, + { + Label: "Unknown Messaging Entry", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/unknownMessagingEntryFBA.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + PrepRequest: addValidSignature, + }, + { + Label: "Not JSON", + URL: "/c/fba/receive", + Data: "not JSON", + ExpectedRespStatus: 200, + ExpectedBodyContains: "unable to parse request JSON", + PrepRequest: addValidSignature, + }, + { + Label: "Invalid URN", + URL: "/c/fba/receive", + Data: string(test.ReadFile("./testdata/fba/invalidURNFBA.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "ignoring request, invalid facebook id", + PrepRequest: addValidSignature, }, } @@ -257,7 +257,7 @@ var testCasesIG = []ChannelHandleTestCase{ URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", + ExpectedBodyContains: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Hello World"), @@ -267,141 +267,141 @@ var testCasesIG = []ChannelHandleTestCase{ PrepRequest: addValidSignature, }, { - Label: "Receive Invalid Signature", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "ignoring request, invalid request signature", - PrepRequest: addInvalidSignature, - }, - { - Label: "No Duplicate Receive Message", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/duplicateMsgIG.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedMsgText: Sp("Hello World"), - ExpectedURN: "instagram:5678", - ExpectedExternalID: "external_id", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature, - }, - { - Label: "Receive Attachment", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/attachmentIG.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedMsgText: Sp(""), - ExpectedAttachments: []string{"https://image-url/foo.png"}, - ExpectedURN: "instagram:5678", - ExpectedExternalID: "external_id", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature, - }, - { - Label: "Receive Like Heart", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/like_heart.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedMsgText: Sp(""), - ExpectedURN: "instagram:5678", - ExpectedExternalID: "external_id", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature, - }, - { - Label: "Receive Icebreaker Get Started", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/icebreakerGetStarted.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - ExpectedURN: "instagram:5678", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - ExpectedEvent: courier.NewConversation, - ExpectedEventExtra: map[string]interface{}{"title": "icebreaker question", "payload": "get_started"}, - PrepRequest: addValidSignature, - }, - { - Label: "Different Page", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/differentPageIG.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: `"data":[]`, - PrepRequest: addValidSignature, - }, - { - Label: "Echo", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/echoIG.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: `ignoring echo`, - PrepRequest: addValidSignature, - }, - { - Label: "No Entries", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/noEntriesIG.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "no entries found", - PrepRequest: addValidSignature, - }, - { - Label: "Not Instagram", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/notInstagram.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notinstagram", - PrepRequest: addValidSignature, - }, - { - Label: "No Messaging Entries", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/noMessagingEntriesIG.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - PrepRequest: addValidSignature, - }, - { - Label: "Unknown Messaging Entry", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/unknownMessagingEntryIG.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", - PrepRequest: addValidSignature, - }, - { - Label: "Not JSON", - URL: "/c/ig/receive", - Data: "not JSON", - ExpectedRespStatus: 200, - ExpectedRespBody: "unable to parse request JSON", - PrepRequest: addValidSignature, - }, - { - Label: "Invalid URN", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/invalidURNIG.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "ignoring request, invalid instagram id", - PrepRequest: addValidSignature, - }, - { - Label: "Story Mention", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/storyMentionIG.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: `ignoring story_mention`, - PrepRequest: addValidSignature, - }, - { - Label: "Message unsent", - URL: "/c/ig/receive", - Data: string(test.ReadFile("./testdata/ig/unsentMsgIG.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: `msg deleted`, - PrepRequest: addValidSignature, + Label: "Receive Invalid Signature", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "ignoring request, invalid request signature", + PrepRequest: addInvalidSignature, + }, + { + Label: "No Duplicate Receive Message", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/duplicateMsgIG.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: "instagram:5678", + ExpectedExternalID: "external_id", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Attachment", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/attachmentIG.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"https://image-url/foo.png"}, + ExpectedURN: "instagram:5678", + ExpectedExternalID: "external_id", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Like Heart", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/like_heart.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgText: Sp(""), + ExpectedURN: "instagram:5678", + ExpectedExternalID: "external_id", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Icebreaker Get Started", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/icebreakerGetStarted.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedURN: "instagram:5678", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + ExpectedEvent: courier.NewConversation, + ExpectedEventExtra: map[string]interface{}{"title": "icebreaker question", "payload": "get_started"}, + PrepRequest: addValidSignature, + }, + { + Label: "Different Page", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/differentPageIG.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: `"data":[]`, + PrepRequest: addValidSignature, + }, + { + Label: "Echo", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/echoIG.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: `ignoring echo`, + PrepRequest: addValidSignature, + }, + { + Label: "No Entries", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/noEntriesIG.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "no entries found", + PrepRequest: addValidSignature, + }, + { + Label: "Not Instagram", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/notInstagram.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "object expected 'page', 'instagram' or 'whatsapp_business_account', found notinstagram", + PrepRequest: addValidSignature, + }, + { + Label: "No Messaging Entries", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/noMessagingEntriesIG.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + PrepRequest: addValidSignature, + }, + { + Label: "Unknown Messaging Entry", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/unknownMessagingEntryIG.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + PrepRequest: addValidSignature, + }, + { + Label: "Not JSON", + URL: "/c/ig/receive", + Data: "not JSON", + ExpectedRespStatus: 200, + ExpectedBodyContains: "unable to parse request JSON", + PrepRequest: addValidSignature, + }, + { + Label: "Invalid URN", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/invalidURNIG.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "ignoring request, invalid instagram id", + PrepRequest: addValidSignature, + }, + { + Label: "Story Mention", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/storyMentionIG.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: `ignoring story_mention`, + PrepRequest: addValidSignature, + }, + { + Label: "Message unsent", + URL: "/c/ig/receive", + Data: string(test.ReadFile("./testdata/ig/unsentMsgIG.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: `msg deleted`, + PrepRequest: addValidSignature, }, } @@ -545,7 +545,7 @@ var testCasesWAC = []ChannelHandleTestCase{ URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/helloWAC.json")), ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", + ExpectedBodyContains: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Hello World"), @@ -559,7 +559,7 @@ var testCasesWAC = []ChannelHandleTestCase{ URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/duplicateWAC.json")), ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", + ExpectedBodyContains: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Hello World"), @@ -573,7 +573,7 @@ var testCasesWAC = []ChannelHandleTestCase{ URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/voiceWAC.json")), ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", + ExpectedBodyContains: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp(""), @@ -588,7 +588,7 @@ var testCasesWAC = []ChannelHandleTestCase{ URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/buttonWAC.json")), ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", + ExpectedBodyContains: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("No"), @@ -602,7 +602,7 @@ var testCasesWAC = []ChannelHandleTestCase{ URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/documentWAC.json")), ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", + ExpectedBodyContains: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("80skaraokesonglistartist"), @@ -617,7 +617,7 @@ var testCasesWAC = []ChannelHandleTestCase{ URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/imageWAC.json")), ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", + ExpectedBodyContains: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Check out my new phone!"), @@ -632,7 +632,7 @@ var testCasesWAC = []ChannelHandleTestCase{ URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/videoWAC.json")), ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", + ExpectedBodyContains: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Check out my new phone!"), @@ -647,7 +647,7 @@ var testCasesWAC = []ChannelHandleTestCase{ URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/audioWAC.json")), ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", + ExpectedBodyContains: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Check out my new phone!"), @@ -658,84 +658,84 @@ var testCasesWAC = []ChannelHandleTestCase{ PrepRequest: addValidSignature, }, { - Label: "Receive Valid Location Message", - URL: wacReceiveURL, - Data: string(test.ReadFile("./testdata/wac/locationWAC.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: `"type":"msg"`, - ExpectedMsgText: Sp(""), - ExpectedAttachments: []string{"geo:0.000000,1.000000"}, - ExpectedURN: "whatsapp:5678", - ExpectedExternalID: "external_id", - ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), - PrepRequest: addValidSignature, + Label: "Receive Valid Location Message", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/locationWAC.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"msg"`, + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"geo:0.000000,1.000000"}, + ExpectedURN: "whatsapp:5678", + ExpectedExternalID: "external_id", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + PrepRequest: addValidSignature, }, { - Label: "Receive Invalid JSON", - URL: wacReceiveURL, - Data: "not json", - ExpectedRespStatus: 200, - ExpectedRespBody: "unable to parse", - PrepRequest: addValidSignature, + Label: "Receive Invalid JSON", + URL: wacReceiveURL, + Data: "not json", + ExpectedRespStatus: 200, + ExpectedBodyContains: "unable to parse", + PrepRequest: addValidSignature, }, { - Label: "Receive Invalid JSON", - URL: wacReceiveURL, - Data: string(test.ReadFile("./testdata/wac/invalidFrom.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "ignoring request, invalid whatsapp id", - PrepRequest: addValidSignature, + Label: "Receive Invalid JSON", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/invalidFrom.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "ignoring request, invalid whatsapp id", + PrepRequest: addValidSignature, }, { - Label: "Receive Invalid JSON", - URL: wacReceiveURL, - Data: string(test.ReadFile("./testdata/wac/invalidTimestamp.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: "ignoring request, invalid timestamp", - PrepRequest: addValidSignature, + Label: "Receive Invalid JSON", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/invalidTimestamp.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "ignoring request, invalid timestamp", + PrepRequest: addValidSignature, }, { Label: "Receive Message WAC invalid signature", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/helloWAC.json")), ExpectedRespStatus: 200, - ExpectedRespBody: "ignoring request, invalid request signature", + ExpectedBodyContains: "ignoring request, invalid request signature", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, PrepRequest: addInvalidSignature, }, { - Label: "Receive Valid Status", - URL: wacReceiveURL, - Data: string(test.ReadFile("./testdata/wac/validStatusWAC.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: `"type":"status"`, - ExpectedMsgStatus: "S", - ExpectedExternalID: "external_id", - PrepRequest: addValidSignature, + Label: "Receive Valid Status", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/validStatusWAC.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"status"`, + ExpectedMsgStatus: "S", + ExpectedExternalID: "external_id", + PrepRequest: addValidSignature, }, { - Label: "Receive Invalid Status", - URL: wacReceiveURL, - Data: string(test.ReadFile("./testdata/wac/invalidStatusWAC.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: `"ignoring request, unknown status: in_orbit"`, - PrepRequest: addValidSignature, + Label: "Receive Invalid Status", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/invalidStatusWAC.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: `"ignoring request, unknown status: in_orbit"`, + PrepRequest: addValidSignature, }, { - Label: "Receive Ignore Status", - URL: wacReceiveURL, - Data: string(test.ReadFile("./testdata/wac/ignoreStatusWAC.json")), - ExpectedRespStatus: 200, - ExpectedRespBody: `"ignoring status: deleted"`, - PrepRequest: addValidSignature, + Label: "Receive Ignore Status", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/ignoreStatusWAC.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: `"ignoring status: deleted"`, + PrepRequest: addValidSignature, }, { Label: "Receive Valid Interactive Button Reply Message", URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/buttonReplyWAC.json")), ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", + ExpectedBodyContains: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Yes"), @@ -749,7 +749,7 @@ var testCasesWAC = []ChannelHandleTestCase{ URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/listReplyWAC.json")), ExpectedRespStatus: 200, - ExpectedRespBody: "Handled", + ExpectedBodyContains: "Handled", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, ExpectedMsgText: Sp("Yes"), @@ -826,33 +826,33 @@ func TestVerify(t *testing.T) { Label: "Valid Secret", URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", ExpectedRespStatus: 200, - ExpectedRespBody: "yarchallenge", + ExpectedBodyContains: "yarchallenge", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, }, { - Label: "Verify No Mode", - URL: "/c/fba/receive", - ExpectedRespStatus: 200, - ExpectedRespBody: "unknown request", + Label: "Verify No Mode", + URL: "/c/fba/receive", + ExpectedRespStatus: 200, + ExpectedBodyContains: "unknown request", }, { - Label: "Verify No Secret", - URL: "/c/fba/receive?hub.mode=subscribe", - ExpectedRespStatus: 200, - ExpectedRespBody: "token does not match secret", + Label: "Verify No Secret", + URL: "/c/fba/receive?hub.mode=subscribe", + ExpectedRespStatus: 200, + ExpectedBodyContains: "token does not match secret", }, { - Label: "Invalid Secret", - URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=blah", - ExpectedRespStatus: 200, - ExpectedRespBody: "token does not match secret", + Label: "Invalid Secret", + URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=blah", + ExpectedRespStatus: 200, + ExpectedBodyContains: "token does not match secret", }, { - Label: "Valid Secret", - URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", - ExpectedRespStatus: 200, - ExpectedRespBody: "yarchallenge", + Label: "Valid Secret", + URL: "/c/fba/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", + ExpectedRespStatus: 200, + ExpectedBodyContains: "yarchallenge", }, }) @@ -861,33 +861,33 @@ func TestVerify(t *testing.T) { Label: "Valid Secret", URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", ExpectedRespStatus: 200, - ExpectedRespBody: "yarchallenge", + ExpectedBodyContains: "yarchallenge", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, }, { - Label: "Verify No Mode", - URL: "/c/ig/receive", - ExpectedRespStatus: 200, - ExpectedRespBody: "unknown request", + Label: "Verify No Mode", + URL: "/c/ig/receive", + ExpectedRespStatus: 200, + ExpectedBodyContains: "unknown request", }, { - Label: "Verify No Secret", - URL: "/c/ig/receive?hub.mode=subscribe", - ExpectedRespStatus: 200, - ExpectedRespBody: "token does not match secret", + Label: "Verify No Secret", + URL: "/c/ig/receive?hub.mode=subscribe", + ExpectedRespStatus: 200, + ExpectedBodyContains: "token does not match secret", }, { - Label: "Invalid Secret", - URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=blah", - ExpectedRespStatus: 200, - ExpectedRespBody: "token does not match secret", + Label: "Invalid Secret", + URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=blah", + ExpectedRespStatus: 200, + ExpectedBodyContains: "token does not match secret", }, { - Label: "Valid Secret", - URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", - ExpectedRespStatus: 200, - ExpectedRespBody: "yarchallenge", + Label: "Valid Secret", + URL: "/c/ig/receive?hub.mode=subscribe&hub.verify_token=fb_webhook_secret&hub.challenge=yarchallenge", + ExpectedRespStatus: 200, + ExpectedBodyContains: "yarchallenge", }, }) } diff --git a/handlers/firebase/firebase_test.go b/handlers/firebase/firebase_test.go index ee4c0f37b..88b776f27 100644 --- a/handlers/firebase/firebase_test.go +++ b/handlers/firebase/firebase_test.go @@ -45,44 +45,44 @@ var testChannels = []courier.Channel{ var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: receiveURL, - Data: "from=12345&date=2017-01-01T08:50:00.000&fcm_token=token&name=fred&msg=hello+world", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("hello world"), - ExpectedURN: "fcm:12345", - ExpectedDate: time.Date(2017, 1, 1, 8, 50, 0, 0, time.UTC), - ExpectedURNAuth: "token", - ExpectedContactName: Sp("fred"), + Label: "Receive Valid Message", + URL: receiveURL, + Data: "from=12345&date=2017-01-01T08:50:00.000&fcm_token=token&name=fred&msg=hello+world", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("hello world"), + ExpectedURN: "fcm:12345", + ExpectedDate: time.Date(2017, 1, 1, 8, 50, 0, 0, time.UTC), + ExpectedURNAuth: "token", + ExpectedContactName: Sp("fred"), }, { - Label: "Receive Invalid Date", - URL: receiveURL, - Data: "from=12345&date=yo&fcm_token=token&name=fred&msg=hello+world", - ExpectedRespStatus: 400, - ExpectedRespBody: "unable to parse date", + Label: "Receive Invalid Date", + URL: receiveURL, + Data: "from=12345&date=yo&fcm_token=token&name=fred&msg=hello+world", + ExpectedRespStatus: 400, + ExpectedBodyContains: "unable to parse date", }, { - Label: "Receive Missing From", - URL: receiveURL, - Data: "date=2017-01-01T08:50:00.000&fcm_token=token&name=fred&msg=hello+world", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'from' required", + Label: "Receive Missing From", + URL: receiveURL, + Data: "date=2017-01-01T08:50:00.000&fcm_token=token&name=fred&msg=hello+world", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'from' required", }, { - Label: "Receive Valid Register", - URL: registerURL, - Data: "urn=12345&fcm_token=token&name=fred", - ExpectedRespStatus: 200, - ExpectedRespBody: "contact_uuid", + Label: "Receive Valid Register", + URL: registerURL, + Data: "urn=12345&fcm_token=token&name=fred", + ExpectedRespStatus: 200, + ExpectedBodyContains: "contact_uuid", }, { - Label: "Receive Missing URN", - URL: registerURL, - Data: "fcm_token=token&name=fred", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'urn' required", + Label: "Receive Missing URN", + URL: registerURL, + Data: "fcm_token=token&name=fred", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'urn' required", }, } diff --git a/handlers/freshchat/freshchat_test.go b/handlers/freshchat/freshchat_test.go index 220f8029c..904abb5cf 100644 --- a/handlers/freshchat/freshchat_test.go +++ b/handlers/freshchat/freshchat_test.go @@ -30,45 +30,45 @@ const ( var sigtestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid w Signature", - Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": validSignature}, - URL: receiveURL, - Data: validReceive, - ExpectedRespStatus: 200, - ExpectedRespBody: "Message Accepted", - ExpectedMsgText: Sp("Test 2"), - ExpectedURN: "freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd", - ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC), + Label: "Receive Valid w Signature", + Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": validSignature}, + URL: receiveURL, + Data: validReceive, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Message Accepted", + ExpectedMsgText: Sp("Test 2"), + ExpectedURN: "freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd", + ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC), }, { - Label: "Bad Signature", - Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": invalidSignature}, - URL: receiveURL, - Data: validReceive, - ExpectedRespStatus: 400, - ExpectedRespBody: `{"message":"Error","data":[{"type":"error","error":"unable to verify signature, crypto/rsa: verification error"}]}`, + Label: "Bad Signature", + Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": invalidSignature}, + URL: receiveURL, + Data: validReceive, + ExpectedRespStatus: 400, + ExpectedBodyContains: `{"message":"Error","data":[{"type":"error","error":"unable to verify signature, crypto/rsa: verification error"}]}`, }, } var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid w Sig", - Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": validSignature}, - URL: receiveURL, - Data: validReceive, - ExpectedRespStatus: 200, - ExpectedRespBody: "Message Accepted", - ExpectedMsgText: Sp("Test 2"), - ExpectedURN: "freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd", - ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC), + Label: "Receive Valid w Sig", + Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": validSignature}, + URL: receiveURL, + Data: validReceive, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Message Accepted", + ExpectedMsgText: Sp("Test 2"), + ExpectedURN: "freshchat:c8fddfaf-622a-4a0e-b060-4f3ccbeab606/882f3926-b292-414b-a411-96380db373cd", + ExpectedDate: time.Date(2019, 6, 21, 17, 43, 20, 866000000, time.UTC), }, { - Label: "Bad JSON", - Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": invalidSignature}, - URL: receiveURL, - Data: "empty", - ExpectedRespStatus: 400, - ExpectedRespBody: `{"message":"Error","data":[{"type":"error","error":"unable to parse request JSON: invalid character 'e' looking for beginning of value"}]}`, + Label: "Bad JSON", + Headers: map[string]string{"Content-Type": "application/json", "X-FreshChat-Signature": invalidSignature}, + URL: receiveURL, + Data: "empty", + ExpectedRespStatus: 400, + ExpectedBodyContains: `{"message":"Error","data":[{"type":"error","error":"unable to parse request JSON: invalid character 'e' looking for beginning of value"}]}`, }, } diff --git a/handlers/globe/globe_test.go b/handlers/globe/globe_test.go index 01b381235..aeedf55b2 100644 --- a/handlers/globe/globe_test.go +++ b/handlers/globe/globe_test.go @@ -111,49 +111,49 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: receiveURL, - Data: validMessage, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("hello world"), - ExpectedURN: "tel:+639171234567", - ExpectedDate: time.Date(2013, 11, 22, 12, 12, 13, 0, time.UTC), + Label: "Receive Valid Message", + URL: receiveURL, + Data: validMessage, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("hello world"), + ExpectedURN: "tel:+639171234567", + ExpectedDate: time.Date(2013, 11, 22, 12, 12, 13, 0, time.UTC), }, { - Label: "No Messages", - URL: receiveURL, - Data: noMessages, - ExpectedRespStatus: 200, - ExpectedRespBody: "Ignored", + Label: "No Messages", + URL: receiveURL, + Data: noMessages, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Ignored", }, { - Label: "Invalid URN", - URL: receiveURL, - Data: invalidURN, - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL, + Data: invalidURN, + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, { - Label: "Invalid Sender", - URL: receiveURL, - Data: invalidSender, - ExpectedRespStatus: 400, - ExpectedRespBody: "invalid 'senderAddress' parameter", + Label: "Invalid Sender", + URL: receiveURL, + Data: invalidSender, + ExpectedRespStatus: 400, + ExpectedBodyContains: "invalid 'senderAddress' parameter", }, { - Label: "Invalid Date", - URL: receiveURL, - Data: invalidDate, - ExpectedRespStatus: 400, - ExpectedRespBody: "parsing time", + Label: "Invalid Date", + URL: receiveURL, + Data: invalidDate, + ExpectedRespStatus: 400, + ExpectedBodyContains: "parsing time", }, { - Label: "Invalid JSON", - URL: receiveURL, - Data: `notjson`, - ExpectedRespStatus: 400, - ExpectedRespBody: "unable to parse request JSON", + Label: "Invalid JSON", + URL: receiveURL, + Data: `notjson`, + ExpectedRespStatus: 400, + ExpectedBodyContains: "unable to parse request JSON", }, } diff --git a/handlers/highconnection/highconnection_test.go b/handlers/highconnection/highconnection_test.go index 0fdefc65e..ec3a8103a 100644 --- a/handlers/highconnection/highconnection_test.go +++ b/handlers/highconnection/highconnection_test.go @@ -21,58 +21,58 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: receiveURL, - Data: "FROM=+33610346460&TO=5151&MESSAGE=Hello+World&RECEPTION_DATE=2015-04-02T14%3A26%3A06", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Hello World"), - ExpectedURN: "tel:+33610346460", - ExpectedDate: time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC), + Label: "Receive Valid Message", + URL: receiveURL, + Data: "FROM=+33610346460&TO=5151&MESSAGE=Hello+World&RECEPTION_DATE=2015-04-02T14%3A26%3A06", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: "tel:+33610346460", + ExpectedDate: time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC), }, { - Label: "Receive Valid Message with accents", - URL: receiveURL, - Data: "FROM=+33610346460&TO=5151&MESSAGE=je+suis+tr%E8s+satisfait+&RECEPTION_DATE=2015-04-02T14%3A26%3A06", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("je suis très satisfait "), - ExpectedURN: "tel:+33610346460", - ExpectedDate: time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC), + Label: "Receive Valid Message with accents", + URL: receiveURL, + Data: "FROM=+33610346460&TO=5151&MESSAGE=je+suis+tr%E8s+satisfait+&RECEPTION_DATE=2015-04-02T14%3A26%3A06", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("je suis très satisfait "), + ExpectedURN: "tel:+33610346460", + ExpectedDate: time.Date(2015, 04, 02, 14, 26, 06, 0, time.UTC), }, { - Label: "Invalid URN", - URL: receiveURL, - Data: "FROM=MTN&TO=5151&MESSAGE=Hello+World&RECEPTION_DATE=2015-04-02T14%3A26%3A06", - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL, + Data: "FROM=MTN&TO=5151&MESSAGE=Hello+World&RECEPTION_DATE=2015-04-02T14%3A26%3A06", + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, { - Label: "Receive Missing Params", - URL: receiveURL, - Data: " ", - ExpectedRespStatus: 400, - ExpectedRespBody: "validation for 'From' failed", + Label: "Receive Missing Params", + URL: receiveURL, + Data: " ", + ExpectedRespStatus: 400, + ExpectedBodyContains: "validation for 'From' failed", }, { - Label: "Receive Invalid Date", - URL: receiveURL, - Data: "FROM=+33610346460&TO=5151&MESSAGE=Hello+World&RECEPTION_DATE=2015-04-02T14:26", - ExpectedRespStatus: 400, - ExpectedRespBody: "cannot parse", + Label: "Receive Invalid Date", + URL: receiveURL, + Data: "FROM=+33610346460&TO=5151&MESSAGE=Hello+World&RECEPTION_DATE=2015-04-02T14:26", + ExpectedRespStatus: 400, + ExpectedBodyContains: "cannot parse", }, { - Label: "Status Missing Params", - URL: statusURL, - ExpectedRespStatus: 400, - ExpectedRespBody: "validation for 'Status' failed", + Label: "Status Missing Params", + URL: statusURL, + ExpectedRespStatus: 400, + ExpectedBodyContains: "validation for 'Status' failed", }, { - Label: "Status Delivered", - URL: statusURL + "?ret_id=12345&status=6", - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"D"`, - ExpectedMsgStatus: courier.MsgDelivered, + Label: "Status Delivered", + URL: statusURL + "?ret_id=12345&status=6", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, }, } diff --git a/handlers/hormuud/hormuud_test.go b/handlers/hormuud/hormuud_test.go index b96e67620..afd922a07 100644 --- a/handlers/hormuud/hormuud_test.go +++ b/handlers/hormuud/hormuud_test.go @@ -27,38 +27,38 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: receiveValidMessage, - Data: "empty", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", - ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC), + Label: "Receive Valid Message", + URL: receiveValidMessage, + Data: "empty", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC), }, { - Label: "Receive Empty Message", - URL: receiveEmptyMessage, - Data: "empty", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp(""), - ExpectedURN: "tel:+2349067554729", - ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC), + Label: "Receive Empty Message", + URL: receiveEmptyMessage, + Data: "empty", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedURN: "tel:+2349067554729", + ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC), }, { - Label: "Receive No Params", - URL: receiveNoParams, - Data: "empty", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'sender' required", + Label: "Receive No Params", + URL: receiveNoParams, + Data: "empty", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'sender' required", }, { - Label: "Invalid URN", - URL: receiveInvalidURN, - Data: "empty", - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveInvalidURN, + Data: "empty", + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, // {Label: "Status No Params", URL: statusNoParams, Status: 400, Response: "field 'status' required"}, // {Label: "Status Invalid Status", URL: statusInvalidStatus, Status: 400, Response: "unknown status '66', must be one of 1,2,4,8,16"}, diff --git a/handlers/i2sms/i2sms_test.go b/handlers/i2sms/i2sms_test.go index 2bb5c1d57..9ffd8e2fd 100644 --- a/handlers/i2sms/i2sms_test.go +++ b/handlers/i2sms/i2sms_test.go @@ -20,20 +20,20 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: "message=Msg&mobile=254791541111", - ExpectedRespStatus: 200, - ExpectedRespBody: "", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+254791541111", + Label: "Receive Valid", + URL: receiveURL, + Data: "message=Msg&mobile=254791541111", + ExpectedRespStatus: 200, + ExpectedBodyContains: "", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+254791541111", }, { - Label: "Receive Missing Number", - URL: receiveURL, - Data: "message=Msg", - ExpectedRespStatus: 400, - ExpectedRespBody: "required field 'mobile'", + Label: "Receive Missing Number", + URL: receiveURL, + Data: "message=Msg", + ExpectedRespStatus: 400, + ExpectedBodyContains: "required field 'mobile'", }, } diff --git a/handlers/infobip/infobip_test.go b/handlers/infobip/infobip_test.go index c662eb3d5..425b318c8 100644 --- a/handlers/infobip/infobip_test.go +++ b/handlers/infobip/infobip_test.go @@ -195,97 +195,97 @@ var invalidStatus = `{ var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: receiveURL, - Data: helloMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("QUIZ Correct answer is Paris"), - ExpectedURN: "tel:+385916242493", - ExpectedExternalID: "817790313235066447", - ExpectedDate: time.Date(2016, 10, 06, 9, 28, 39, 220000000, time.FixedZone("", 0)), + Label: "Receive Valid Message", + URL: receiveURL, + Data: helloMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("QUIZ Correct answer is Paris"), + ExpectedURN: "tel:+385916242493", + ExpectedExternalID: "817790313235066447", + ExpectedDate: time.Date(2016, 10, 06, 9, 28, 39, 220000000, time.FixedZone("", 0)), }, { - Label: "Receive missing results key", - URL: receiveURL, - Data: missingResults, - ExpectedRespStatus: 400, - ExpectedRespBody: "validation for 'Results' failed", + Label: "Receive missing results key", + URL: receiveURL, + Data: missingResults, + ExpectedRespStatus: 400, + ExpectedBodyContains: "validation for 'Results' failed", }, { - Label: "Receive missing text key", - URL: receiveURL, - Data: missingText, - ExpectedRespStatus: 200, - ExpectedRespBody: "ignoring request, no message", + Label: "Receive missing text key", + URL: receiveURL, + Data: missingText, + ExpectedRespStatus: 200, + ExpectedBodyContains: "ignoring request, no message", }, { - Label: "Invalid URN", - URL: receiveURL, - Data: invalidURN, - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL, + Data: invalidURN, + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, { - Label: "Status report invalid JSON", - URL: statusURL, - Data: invalidJSONStatus, - ExpectedRespStatus: 400, - ExpectedRespBody: "unable to parse request JSON", + Label: "Status report invalid JSON", + URL: statusURL, + Data: invalidJSONStatus, + ExpectedRespStatus: 400, + ExpectedBodyContains: "unable to parse request JSON", }, { - Label: "Status report missing results key", - URL: statusURL, - Data: statusMissingResultsKey, - ExpectedRespStatus: 400, - ExpectedRespBody: "Field validation for 'Results' failed", + Label: "Status report missing results key", + URL: statusURL, + Data: statusMissingResultsKey, + ExpectedRespStatus: 400, + ExpectedBodyContains: "Field validation for 'Results' failed", }, { - Label: "Status delivered", - URL: statusURL, - Data: validStatusDelivered, - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"D"`, - ExpectedMsgStatus: courier.MsgDelivered, + Label: "Status delivered", + URL: statusURL, + Data: validStatusDelivered, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, }, { - Label: "Status rejected", - URL: statusURL, - Data: validStatusRejected, - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"F"`, - ExpectedMsgStatus: courier.MsgFailed, + Label: "Status rejected", + URL: statusURL, + Data: validStatusRejected, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, }, { - Label: "Status undeliverable", - URL: statusURL, - Data: validStatusUndeliverable, - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"F"`, - ExpectedMsgStatus: courier.MsgFailed, + Label: "Status undeliverable", + URL: statusURL, + Data: validStatusUndeliverable, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, }, { - Label: "Status pending", - URL: statusURL, - Data: validStatusPending, - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"S"`, - ExpectedMsgStatus: courier.MsgSent, + Label: "Status pending", + URL: statusURL, + Data: validStatusPending, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, }, { - Label: "Status expired", - URL: statusURL, - Data: validStatusExpired, - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"S"`, - ExpectedMsgStatus: courier.MsgSent, + Label: "Status expired", + URL: statusURL, + Data: validStatusExpired, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, }, { - Label: "Status group name unexpected", - URL: statusURL, - Data: invalidStatus, - ExpectedRespStatus: 400, - ExpectedRespBody: `unknown status 'UNEXPECTED'`, + Label: "Status group name unexpected", + URL: statusURL, + Data: invalidStatus, + ExpectedRespStatus: 400, + ExpectedBodyContains: `unknown status 'UNEXPECTED'`, }, } diff --git a/handlers/jasmin/jasmin_test.go b/handlers/jasmin/jasmin_test.go index b2c4303a3..3bd11a6d9 100644 --- a/handlers/jasmin/jasmin_test.go +++ b/handlers/jasmin/jasmin_test.go @@ -21,60 +21,60 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: receiveURL, - Data: "content=%05v%05nement&coding=0&From=2349067554729&To=2349067554711&id=1001", - ExpectedRespStatus: 200, - ExpectedRespBody: "ACK/Jasmin", - ExpectedMsgText: Sp("événement"), - ExpectedURN: "tel:+2349067554729", - ExpectedExternalID: "1001", + Label: "Receive Valid Message", + URL: receiveURL, + Data: "content=%05v%05nement&coding=0&From=2349067554729&To=2349067554711&id=1001", + ExpectedRespStatus: 200, + ExpectedBodyContains: "ACK/Jasmin", + ExpectedMsgText: Sp("événement"), + ExpectedURN: "tel:+2349067554729", + ExpectedExternalID: "1001", }, { - Label: "Receive Missing To", - URL: receiveURL, - Data: "content=%05v%05nement&coding=0&From=2349067554729&id=1001", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'to' required", + Label: "Receive Missing To", + URL: receiveURL, + Data: "content=%05v%05nement&coding=0&From=2349067554729&id=1001", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'to' required", }, { - Label: "Invalid URN", - URL: receiveURL, - Data: "content=%05v%05nement&coding=0&From=MTN&To=2349067554711&id=1001", - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Invalid URN", + URL: receiveURL, + Data: "content=%05v%05nement&coding=0&From=MTN&To=2349067554711&id=1001", + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, { - Label: "Status Delivered", - URL: statusURL, - Data: "id=external1&dlvrd=1", - ExpectedRespStatus: 200, - ExpectedRespBody: "ACK/Jasmin", - ExpectedMsgStatus: "D", - ExpectedExternalID: "external1", + Label: "Status Delivered", + URL: statusURL, + Data: "id=external1&dlvrd=1", + ExpectedRespStatus: 200, + ExpectedBodyContains: "ACK/Jasmin", + ExpectedMsgStatus: "D", + ExpectedExternalID: "external1", }, { - Label: "Status Failed", - URL: statusURL, - Data: "id=external1&err=1", - ExpectedRespStatus: 200, - ExpectedRespBody: "ACK/Jasmin", - ExpectedMsgStatus: "F", - ExpectedExternalID: "external1", + Label: "Status Failed", + URL: statusURL, + Data: "id=external1&err=1", + ExpectedRespStatus: 200, + ExpectedBodyContains: "ACK/Jasmin", + ExpectedMsgStatus: "F", + ExpectedExternalID: "external1", }, { - Label: "Status Missing", - URL: statusURL, - ExpectedRespStatus: 400, - Data: "nothing", - ExpectedRespBody: "field 'id' required", + Label: "Status Missing", + URL: statusURL, + ExpectedRespStatus: 400, + Data: "nothing", + ExpectedBodyContains: "field 'id' required", }, { - Label: "Status Unknown", - URL: statusURL, - ExpectedRespStatus: 400, - Data: "id=external1&err=0&dlvrd=0", - ExpectedRespBody: "must have either dlvrd or err set to 1", + Label: "Status Unknown", + URL: statusURL, + ExpectedRespStatus: 400, + Data: "id=external1&err=0&dlvrd=0", + ExpectedBodyContains: "must have either dlvrd or err set to 1", }, } diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index 266a697a3..fc84108a3 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -144,28 +144,28 @@ func addInvalidSignature(r *http.Request) { } var testCases = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("Simple Message"), ExpectedURN: "jiochat:1234", ExpectedExternalID: "123456", ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "invalid jiochat id"}, - {Label: "Missing params", URL: receiveURL, Data: missingParamsRequired, ExpectedRespStatus: 400, ExpectedRespBody: "Error:Field validation"}, - {Label: "Missing params Event or MsgId", URL: receiveURL, Data: missingParams, ExpectedRespStatus: 400, ExpectedRespBody: "missing parameters, must have either 'MsgId' or 'Event'"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid jiochat id"}, + {Label: "Missing params", URL: receiveURL, Data: missingParamsRequired, ExpectedRespStatus: 400, ExpectedBodyContains: "Error:Field validation"}, + {Label: "Missing params Event or MsgId", URL: receiveURL, Data: missingParams, ExpectedRespStatus: 400, ExpectedBodyContains: "missing parameters, must have either 'MsgId' or 'Event'"}, - {Label: "Receive Image", URL: receiveURL, Data: imageMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Image", URL: receiveURL, Data: imageMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp(""), ExpectedURN: "jiochat:1234", ExpectedExternalID: "123456", ExpectedAttachments: []string{"https://channels.jiochat.com/media/download.action?media_id=12"}, ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, - {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedRespStatus: 200, ExpectedRespBody: "Event Accepted", + {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "Event Accepted", ExpectedEvent: courier.NewConversation, ExpectedURN: "jiochat:1234"}, - {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, ExpectedRespStatus: 200, ExpectedRespBody: "unknown event"}, + {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "unknown event"}, - {Label: "Verify URL", URL: verifyURL, ExpectedRespStatus: 200, ExpectedRespBody: "SUCCESS", + {Label: "Verify URL", URL: verifyURL, ExpectedRespStatus: 200, ExpectedBodyContains: "SUCCESS", PrepRequest: addValidSignature}, - {Label: "Verify URL Invalid signature", URL: verifyURL, ExpectedRespStatus: 400, ExpectedRespBody: "unknown request", + {Label: "Verify URL Invalid signature", URL: verifyURL, ExpectedRespStatus: 400, ExpectedBodyContains: "unknown request", PrepRequest: addInvalidSignature}, } @@ -194,27 +194,27 @@ func TestFetchAccessToken(t *testing.T) { RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ { - Label: "Receive Message", - URL: receiveURL, - Data: validMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Simple Message"), - ExpectedURN: "jiochat:1234", + Label: "Receive Message", + URL: receiveURL, + Data: validMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Simple Message"), + ExpectedURN: "jiochat:1234", }, { - Label: "Verify URL", - URL: verifyURL, - ExpectedRespStatus: 200, - ExpectedRespBody: "SUCCESS", - PrepRequest: addValidSignature, + Label: "Verify URL", + URL: verifyURL, + ExpectedRespStatus: 200, + ExpectedBodyContains: "SUCCESS", + PrepRequest: addValidSignature, }, { - Label: "Verify URL Invalid signature", - URL: verifyURL, - ExpectedRespStatus: 400, - ExpectedRespBody: "unknown request", - PrepRequest: addInvalidSignature}, + Label: "Verify URL Invalid signature", + URL: verifyURL, + ExpectedRespStatus: 400, + ExpectedBodyContains: "unknown request", + PrepRequest: addInvalidSignature}, }) // wait for our fetch to be called diff --git a/handlers/junebug/junebug_test.go b/handlers/junebug/junebug_test.go index 1d8dbf176..dfaba63ef 100644 --- a/handlers/junebug/junebug_test.go +++ b/handlers/junebug/junebug_test.go @@ -94,44 +94,44 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: inboundURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Message", URL: inboundURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("hello world"), ExpectedURN: "tel:+250788383383", ExpectedDate: time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC)}, {Label: "Invalid URN", URL: inboundURL, Data: invalidURN, - ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, + ExpectedRespStatus: 400, ExpectedBodyContains: "phone number supplied is not a number"}, {Label: "Invalid Timestamp", URL: inboundURL, Data: invalidTimestamp, - ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse date"}, + ExpectedRespStatus: 400, ExpectedBodyContains: "unable to parse date"}, {Label: "Missing Message ID", URL: inboundURL, Data: missingMessageID, - ExpectedRespStatus: 400, ExpectedRespBody: "'MessageID' failed on the 'required'"}, + ExpectedRespStatus: 400, ExpectedBodyContains: "'MessageID' failed on the 'required'"}, - {Label: "Receive Pending Event", URL: eventURL, Data: pendingEvent, ExpectedRespStatus: 200, ExpectedRespBody: "Ignored"}, - {Label: "Receive Sent Event", URL: eventURL, Data: sentEvent, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Pending Event", URL: eventURL, Data: pendingEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "Ignored"}, + {Label: "Receive Sent Event", URL: eventURL, Data: sentEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedExternalID: "xx12345", ExpectedMsgStatus: "S"}, - {Label: "Receive Delivered Event", URL: eventURL, Data: deliveredEvent, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Delivered Event", URL: eventURL, Data: deliveredEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedExternalID: "xx12345", ExpectedMsgStatus: "D"}, - {Label: "Receive Failed Event", URL: eventURL, Data: failedEvent, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Failed Event", URL: eventURL, Data: failedEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedExternalID: "xx12345", ExpectedMsgStatus: "F"}, - {Label: "Receive Unknown Event", URL: eventURL, Data: unknownEvent, ExpectedRespStatus: 200, ExpectedRespBody: "Ignored"}, + {Label: "Receive Unknown Event", URL: eventURL, Data: unknownEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "Ignored"}, - {Label: "Receive Invalid JSON", URL: eventURL, Data: "not json", ExpectedRespStatus: 400, ExpectedRespBody: "Error"}, - {Label: "Receive Missing Event Type", URL: eventURL, Data: missingEventType, ExpectedRespStatus: 400, ExpectedRespBody: "Error"}, + {Label: "Receive Invalid JSON", URL: eventURL, Data: "not json", ExpectedRespStatus: 400, ExpectedBodyContains: "Error"}, + {Label: "Receive Missing Event Type", URL: eventURL, Data: missingEventType, ExpectedRespStatus: 400, ExpectedBodyContains: "Error"}, } var authenticatedTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: inboundURL, Data: validMsg, Headers: map[string]string{"Authorization": "Token sesame"}, - ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("hello world"), ExpectedURN: "tel:+250788383383", ExpectedDate: time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC)}, {Label: "Invalid Incoming Authorization", URL: inboundURL, Data: validMsg, Headers: map[string]string{"Authorization": "Token foo"}, - ExpectedRespStatus: 401, ExpectedRespBody: "Unauthorized"}, + ExpectedRespStatus: 401, ExpectedBodyContains: "Unauthorized"}, {Label: "Receive Sent Event", URL: eventURL, Data: sentEvent, Headers: map[string]string{"Authorization": "Token sesame"}, - ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedExternalID: "xx12345", ExpectedMsgStatus: "S"}, {Label: "Invalid Incoming Authorization", URL: eventURL, Data: sentEvent, Headers: map[string]string{"Authorization": "Token foo"}, - ExpectedRespStatus: 401, ExpectedRespBody: "Unauthorized"}, + ExpectedRespStatus: 401, ExpectedBodyContains: "Unauthorized"}, } func TestHandler(t *testing.T) { diff --git a/handlers/kaleyra/kaleyra_test.go b/handlers/kaleyra/kaleyra_test.go index a574c5397..6b4954b2f 100644 --- a/handlers/kaleyra/kaleyra_test.go +++ b/handlers/kaleyra/kaleyra_test.go @@ -29,76 +29,76 @@ var testChannels = []courier.Channel{ var testCases = []ChannelHandleTestCase{ { - Label: "Receive Msg", - URL: receiveMsgURL + "?created_at=1603914166&type=text&from=14133881111&name=John%20Cruz&body=Hello%20World", - ExpectedContactName: Sp("John Cruz"), - ExpectedURN: "whatsapp:14133881111", - ExpectedMsgText: Sp("Hello World"), - ExpectedAttachments: []string{}, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", + Label: "Receive Msg", + URL: receiveMsgURL + "?created_at=1603914166&type=text&from=14133881111&name=John%20Cruz&body=Hello%20World", + ExpectedContactName: Sp("John Cruz"), + ExpectedURN: "whatsapp:14133881111", + ExpectedMsgText: Sp("Hello World"), + ExpectedAttachments: []string{}, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", }, { - Label: "Receive Media", - URL: receiveMsgURL + "?created_at=1603914166&type=image&from=14133881111&name=John%20Cruz&media_url=https://link.to/image.jpg", - ExpectedContactName: Sp("John Cruz"), - ExpectedURN: "whatsapp:14133881111", - ExpectedMsgText: Sp(""), - ExpectedAttachments: []string{"https://link.to/image.jpg"}, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", + Label: "Receive Media", + URL: receiveMsgURL + "?created_at=1603914166&type=image&from=14133881111&name=John%20Cruz&media_url=https://link.to/image.jpg", + ExpectedContactName: Sp("John Cruz"), + ExpectedURN: "whatsapp:14133881111", + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"https://link.to/image.jpg"}, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", }, { - Label: "Receive Empty", - URL: receiveMsgURL + "?created_at=1603914166&type=text&from=14133881111&name=John%20Cruz", - ExpectedRespStatus: 400, - ExpectedRespBody: "no text or media", + Label: "Receive Empty", + URL: receiveMsgURL + "?created_at=1603914166&type=text&from=14133881111&name=John%20Cruz", + ExpectedRespStatus: 400, + ExpectedBodyContains: "no text or media", }, { - Label: "Receive Invalid CreatedAt", - URL: receiveMsgURL + "?created_at=nottimestamp&type=text&from=14133881111&name=John%20Cruz&body=Hi", - ExpectedContactName: Sp("John Cruz"), - ExpectedRespStatus: 400, - ExpectedRespBody: "invalid created_at", + Label: "Receive Invalid CreatedAt", + URL: receiveMsgURL + "?created_at=nottimestamp&type=text&from=14133881111&name=John%20Cruz&body=Hi", + ExpectedContactName: Sp("John Cruz"), + ExpectedRespStatus: 400, + ExpectedBodyContains: "invalid created_at", }, { - Label: "Receive Invalid Type", - URL: receiveMsgURL + "?created_at=1603914166&type=sticker&from=14133881111&name=John%20Cruz", - ExpectedRespStatus: 200, - ExpectedRespBody: "unknown message type", + Label: "Receive Invalid Type", + URL: receiveMsgURL + "?created_at=1603914166&type=sticker&from=14133881111&name=John%20Cruz", + ExpectedRespStatus: 200, + ExpectedBodyContains: "unknown message type", }, { - Label: "Receive Invalid From", - URL: receiveMsgURL + "?created_at=1603914166&type=text&from=notnumber&name=John%20Cruz&body=Hi", - ExpectedContactName: Sp("John Cruz"), - ExpectedRespStatus: 400, - ExpectedRespBody: "invalid whatsapp id", + Label: "Receive Invalid From", + URL: receiveMsgURL + "?created_at=1603914166&type=text&from=notnumber&name=John%20Cruz&body=Hi", + ExpectedContactName: Sp("John Cruz"), + ExpectedRespStatus: 400, + ExpectedBodyContains: "invalid whatsapp id", }, { - Label: "Receive Blank From", - URL: receiveMsgURL, - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'from' required", + Label: "Receive Blank From", + URL: receiveMsgURL, + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'from' required", }, { - Label: "Receive Valid Status", - URL: receiveStatusURL + "?id=58f86fab-85c5-4f7c-9b68-9c323248afc4%3A0&status=read", - ExpectedExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", - ExpectedMsgStatus: "D", - ExpectedRespStatus: 200, - ExpectedRespBody: `"type":"status"`, + Label: "Receive Valid Status", + URL: receiveStatusURL + "?id=58f86fab-85c5-4f7c-9b68-9c323248afc4%3A0&status=read", + ExpectedExternalID: "58f86fab-85c5-4f7c-9b68-9c323248afc4:0", + ExpectedMsgStatus: "D", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"status"`, }, { - Label: "Receive Invalid Status", - URL: receiveStatusURL + "?id=58f86fab-85c5-4f7c-9b68-9c323248afc4%3A0&status=deleted", - ExpectedRespStatus: 200, - ExpectedRespBody: "unknown status", + Label: "Receive Invalid Status", + URL: receiveStatusURL + "?id=58f86fab-85c5-4f7c-9b68-9c323248afc4%3A0&status=deleted", + ExpectedRespStatus: 200, + ExpectedBodyContains: "unknown status", }, { - Label: "Receive Blank status", - URL: receiveStatusURL, - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'status' required", + Label: "Receive Blank status", + URL: receiveStatusURL, + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'status' required", }, } diff --git a/handlers/kannel/kannel_test.go b/handlers/kannel/kannel_test.go index 4378fe8b6..a020e95d9 100644 --- a/handlers/kannel/kannel_test.go +++ b/handlers/kannel/kannel_test.go @@ -32,25 +32,25 @@ var ignoreChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Receive KI Message", URL: receiveKIMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive KI Message", URL: receiveKIMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+68673076228", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp(""), ExpectedURN: "tel:+2349067554729", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "field 'sender' required"}, - {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, - {Label: "Status No Params", URL: statusNoParams, ExpectedRespStatus: 400, ExpectedRespBody: "field 'status' required"}, - {Label: "Status Invalid Status", URL: statusInvalidStatus, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status '66', must be one of 1,2,4,8,16"}, - {Label: "Status Valid", URL: statusWired, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, ExpectedMsgStatus: courier.MsgSent}, + {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedRespStatus: 400, ExpectedBodyContains: "field 'sender' required"}, + {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedRespStatus: 400, ExpectedBodyContains: "phone number supplied is not a number"}, + {Label: "Status No Params", URL: statusNoParams, ExpectedRespStatus: 400, ExpectedBodyContains: "field 'status' required"}, + {Label: "Status Invalid Status", URL: statusInvalidStatus, ExpectedRespStatus: 400, ExpectedBodyContains: "unknown status '66', must be one of 1,2,4,8,16"}, + {Label: "Status Valid", URL: statusWired, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"S"`, ExpectedMsgStatus: courier.MsgSent}, } var ignoreTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Write Status Delivered", URL: statusDelivered, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered}, - {Label: "Ignore Status Wired", URL: statusWired, ExpectedRespStatus: 200, ExpectedRespBody: `ignoring sent report`}, - {Label: "Ignore Status Sent", URL: statusSent, ExpectedRespStatus: 200, ExpectedRespBody: `ignoring sent report`}, + {Label: "Write Status Delivered", URL: statusDelivered, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered}, + {Label: "Ignore Status Wired", URL: statusWired, ExpectedRespStatus: 200, ExpectedBodyContains: `ignoring sent report`}, + {Label: "Ignore Status Sent", URL: statusSent, ExpectedRespStatus: 200, ExpectedBodyContains: `ignoring sent report`}, } func TestHandler(t *testing.T) { diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index 8e25bcf0e..7851ceaa6 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -258,37 +258,37 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("Hello, world"), ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, - {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessageLast, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessageLast, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("Last event"), ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, - {Label: "Receive Valid Image Message", URL: receiveURL, Data: receiveValidImageMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Image Message", URL: receiveURL, Data: receiveValidImageMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, - {Label: "Receive Valid Video Message", URL: receiveURL, Data: receiveValidVideoMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Video Message", URL: receiveURL, Data: receiveValidVideoMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, - {Label: "Receive Valid Video External Message", URL: receiveURL, Data: receiveValidVideoExternalMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Video External Message", URL: receiveURL, Data: receiveValidVideoExternalMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://example.com/original.mp4"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, - {Label: "Receive Valid Audio Message", URL: receiveURL, Data: receiveValidAudioMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Audio Message", URL: receiveURL, Data: receiveValidAudioMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, - {Label: "Receive Valid Location Message", URL: receiveURL, Data: receiveValidLocationMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Location Message", URL: receiveURL, Data: receiveValidLocationMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("my location"), ExpectedAttachments: []string{"geo:35.687574,139.729220"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), PrepRequest: addValidSignature}, - {Label: "Missing message", URL: receiveURL, Data: missingMessage, ExpectedRespStatus: 200, ExpectedRespBody: "ignoring request, no message", + {Label: "Missing message", URL: receiveURL, Data: missingMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "ignoring request, no message", PrepRequest: addValidSignature}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "invalid line id", + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid line id", PrepRequest: addValidSignature}, - {Label: "No event request", URL: receiveURL, Data: noEvent, ExpectedRespStatus: 200, ExpectedRespBody: "ignoring request, no message", + {Label: "No event request", URL: receiveURL, Data: noEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "ignoring request, no message", PrepRequest: addValidSignature}, - {Label: "Receive Valid Message Invalid signature", URL: receiveURL, Data: receiveValidMessage, ExpectedRespStatus: 400, ExpectedRespBody: "invalid request signature", + {Label: "Receive Valid Message Invalid signature", URL: receiveURL, Data: receiveValidMessage, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid request signature", PrepRequest: addInvalidSignature}, } diff --git a/handlers/m3tech/m3tech_test.go b/handlers/m3tech/m3tech_test.go index 58561d80f..1556fbbc0 100644 --- a/handlers/m3tech/m3tech_test.go +++ b/handlers/m3tech/m3tech_test.go @@ -15,27 +15,27 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?from=+923161909799&text=hello+world", - Data: " ", - ExpectedRespStatus: 200, - ExpectedRespBody: "SMS Accepted", - ExpectedMsgText: Sp("hello world"), - ExpectedURN: "tel:+923161909799", + Label: "Receive Valid Message", + URL: "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?from=+923161909799&text=hello+world", + Data: " ", + ExpectedRespStatus: 200, + ExpectedBodyContains: "SMS Accepted", + ExpectedMsgText: Sp("hello world"), + ExpectedURN: "tel:+923161909799", }, { - Label: "Invalid URN", - URL: "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?from=MTN&text=hello+world", - Data: " ", - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Invalid URN", + URL: "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?from=MTN&text=hello+world", + Data: " ", + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, { - Label: "Receive No From", - URL: "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?text=hello", - Data: " ", - ExpectedRespStatus: 400, - ExpectedRespBody: "missing required field 'from'", + Label: "Receive No From", + URL: "/c/m3/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?text=hello", + Data: " ", + ExpectedRespStatus: 400, + ExpectedBodyContains: "missing required field 'from'", }, } diff --git a/handlers/macrokiosk/macrokiosk_test.go b/handlers/macrokiosk/macrokiosk_test.go index bde14a082..a532b7b46 100644 --- a/handlers/macrokiosk/macrokiosk_test.go +++ b/handlers/macrokiosk/macrokiosk_test.go @@ -31,23 +31,23 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "-1", + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedBodyContains: "-1", ExpectedMsgText: Sp("Hello"), ExpectedURN: "tel:+60124361111", ExpectedDate: time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC), ExpectedExternalID: "abc1234"}, - {Label: "Receive Valid via GET", URL: receiveURL + "?" + validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "-1", + {Label: "Receive Valid via GET", URL: receiveURL + "?" + validReceive, ExpectedRespStatus: 200, ExpectedBodyContains: "-1", ExpectedMsgText: Sp("Hello"), ExpectedURN: "tel:+60124361111", ExpectedDate: time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC), ExpectedExternalID: "abc1234"}, - {Label: "Receive Valid", URL: receiveURL, Data: validLongcodeReceive, ExpectedRespStatus: 200, ExpectedRespBody: "-1", + {Label: "Receive Valid", URL: receiveURL, Data: validLongcodeReceive, ExpectedRespStatus: 200, ExpectedBodyContains: "-1", ExpectedMsgText: Sp("Hello"), ExpectedURN: "tel:+60124361111", ExpectedDate: time.Date(2016, 3, 30, 11, 33, 06, 0, time.UTC), ExpectedExternalID: "abc1234"}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, - {Label: "Missing Params", URL: receiveURL, Data: missingParamsReceive, ExpectedRespStatus: 400, ExpectedRespBody: "missing shortcode, longcode, from or msisdn parameters"}, - {Label: "Invalid Params", URL: receiveURL, Data: invalidParamsReceive, ExpectedRespStatus: 400, ExpectedRespBody: "missing shortcode, longcode, from or msisdn parameters"}, - {Label: "Invalid Address Params", URL: receiveURL, Data: invalidAddress, ExpectedRespStatus: 400, ExpectedRespBody: "invalid to number [1515], expecting [2020]"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedBodyContains: "phone number supplied is not a number"}, + {Label: "Missing Params", URL: receiveURL, Data: missingParamsReceive, ExpectedRespStatus: 400, ExpectedBodyContains: "missing shortcode, longcode, from or msisdn parameters"}, + {Label: "Invalid Params", URL: receiveURL, Data: invalidParamsReceive, ExpectedRespStatus: 400, ExpectedBodyContains: "missing shortcode, longcode, from or msisdn parameters"}, + {Label: "Invalid Address Params", URL: receiveURL, Data: invalidAddress, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid to number [1515], expecting [2020]"}, - {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, ExpectedMsgStatus: courier.MsgSent}, - {Label: "Wired Status", URL: statusURL, Data: processingStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"W"`, ExpectedMsgStatus: courier.MsgWired}, - {Label: "Unknown Status", URL: statusURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedRespBody: `ignoring unknown status 'UNKNOWN'`}, + {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"S"`, ExpectedMsgStatus: courier.MsgSent}, + {Label: "Wired Status", URL: statusURL, Data: processingStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"W"`, ExpectedMsgStatus: courier.MsgWired}, + {Label: "Unknown Status", URL: statusURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `ignoring unknown status 'UNKNOWN'`}, } func TestHandler(t *testing.T) { diff --git a/handlers/mblox/mblox_test.go b/handlers/mblox/mblox_test.go index f8cb71044..faa724119 100644 --- a/handlers/mblox/mblox_test.go +++ b/handlers/mblox/mblox_test.go @@ -62,16 +62,16 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedBodyContains: "Message Accepted", ExpectedMsgText: Sp("Hello World"), ExpectedURN: "tel:+12067799294", ExpectedDate: time.Date(2016, 3, 30, 19, 33, 06, 643000000, time.UTC), ExpectedExternalID: "OzQ5UqIOdoY8"}, - {Label: "Receive Missing Params", URL: receiveURL, Data: missingParamsRecieve, ExpectedRespStatus: 400, ExpectedRespBody: "missing one of 'id', 'from', 'to', 'body' or 'received_at' in request body"}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, + {Label: "Receive Missing Params", URL: receiveURL, Data: missingParamsRecieve, ExpectedRespStatus: 400, ExpectedBodyContains: "missing one of 'id', 'from', 'to', 'body' or 'received_at' in request body"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedBodyContains: "phone number supplied is not a number"}, - {Label: "Status Valid", URL: receiveURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered}, - {Label: "Status Unknown", URL: receiveURL, Data: unknownStatus, ExpectedRespStatus: 400, ExpectedRespBody: `unknown status 'INVALID'`}, - {Label: "Status Missing Batch ID", URL: receiveURL, Data: missingBatchID, ExpectedRespStatus: 400, ExpectedRespBody: "missing one of 'batch_id' or 'status' in request body"}, + {Label: "Status Valid", URL: receiveURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered}, + {Label: "Status Unknown", URL: receiveURL, Data: unknownStatus, ExpectedRespStatus: 400, ExpectedBodyContains: `unknown status 'INVALID'`}, + {Label: "Status Missing Batch ID", URL: receiveURL, Data: missingBatchID, ExpectedRespStatus: 400, ExpectedBodyContains: "missing one of 'batch_id' or 'status' in request body"}, } func TestHandler(t *testing.T) { diff --git a/handlers/messangi/messangi_test.go b/handlers/messangi/messangi_test.go index e9f4e2939..98b3bff30 100644 --- a/handlers/messangi/messangi_test.go +++ b/handlers/messangi/messangi_test.go @@ -19,19 +19,19 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: "mo=Msg&mobile=18765422035", - ExpectedRespStatus: 200, - ExpectedRespBody: "Message Accepted", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+18765422035"}, + Label: "Receive Valid", + URL: receiveURL, + Data: "mo=Msg&mobile=18765422035", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+18765422035"}, { - Label: "Receive Missing Number", - URL: receiveURL, - Data: "mo=Msg", - ExpectedRespStatus: 400, - ExpectedRespBody: "required field 'mobile'"}, + Label: "Receive Missing Number", + URL: receiveURL, + Data: "mo=Msg", + ExpectedRespStatus: 400, + ExpectedBodyContains: "required field 'mobile'"}, } func TestHandler(t *testing.T) { diff --git a/handlers/mtarget/mtarget_test.go b/handlers/mtarget/mtarget_test.go index bfe7dbbb5..7ca841050 100644 --- a/handlers/mtarget/mtarget_test.go +++ b/handlers/mtarget/mtarget_test.go @@ -32,22 +32,22 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("hello world"), ExpectedURN: "tel:+923161909799"}, - {Label: "Invalid URN", URL: receiveURL, Data: receiveInvalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, - {Label: "Receive Stop", URL: receiveURL, Data: receiveStop, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Invalid URN", URL: receiveURL, Data: receiveInvalidURN, ExpectedRespStatus: 400, ExpectedBodyContains: "phone number supplied is not a number"}, + {Label: "Receive Stop", URL: receiveURL, Data: receiveStop, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedURN: "tel:+923161909799", ExpectedEvent: courier.StopContact}, - {Label: "Receive Missing From", URL: receiveURL, Data: receiveMissingFrom, ExpectedRespStatus: 400, ExpectedRespBody: "missing required field 'Msisdn'"}, + {Label: "Receive Missing From", URL: receiveURL, Data: receiveMissingFrom, ExpectedRespStatus: 400, ExpectedBodyContains: "missing required field 'Msisdn'"}, - {Label: "Receive Part 2", URL: receiveURL, Data: receivePart2, ExpectedRespStatus: 200, ExpectedRespBody: "received"}, - {Label: "Receive Part 1", URL: receiveURL, Data: receivePart1, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Part 2", URL: receiveURL, Data: receivePart2, ExpectedRespStatus: 200, ExpectedBodyContains: "received"}, + {Label: "Receive Part 1", URL: receiveURL, Data: receivePart1, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("hello world"), ExpectedURN: "tel:+923161909799"}, - {Label: "Status Delivered", URL: statusURL, Data: statusDelivered, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Status Delivered", URL: statusURL, Data: statusDelivered, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedExternalID: "12a7ee90-50ce-11e7-80ae-00000a0a643c", ExpectedMsgStatus: "D"}, - {Label: "Status Failed", URL: statusURL, Data: statusFailed, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Status Failed", URL: statusURL, Data: statusFailed, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedExternalID: "12a7ee90-50ce-11e7-80ae-00000a0a643c", ExpectedMsgStatus: "F"}, - {Label: "Status Missing ID", URL: statusURL, Data: statusMissingID, ExpectedRespStatus: 400, ExpectedRespBody: "missing required field 'MsgId'"}, + {Label: "Status Missing ID", URL: statusURL, Data: statusMissingID, ExpectedRespStatus: 400, ExpectedBodyContains: "missing required field 'MsgId'"}, } func TestHandler(t *testing.T) { diff --git a/handlers/nexmo/nexmo_test.go b/handlers/nexmo/nexmo_test.go index ee95a4050..66d2a9545 100644 --- a/handlers/nexmo/nexmo_test.go +++ b/handlers/nexmo/nexmo_test.go @@ -20,85 +20,85 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Valid Receive", - URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?to=2020&msisdn=2349067554729&text=Join&messageId=external1", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", + Label: "Valid Receive", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?to=2020&msisdn=2349067554729&text=Join&messageId=external1", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", }, { - Label: "Invalid URN", - URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?to=2020&msisdn=MTN&text=Join&messageId=external1", - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Invalid URN", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive?to=2020&msisdn=MTN&text=Join&messageId=external1", + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, { - Label: "Valid Receive Post", - URL: receiveURL, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - Data: "to=2020&msisdn=2349067554729&text=Join&messageId=external1", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", + Label: "Valid Receive Post", + URL: receiveURL, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + Data: "to=2020&msisdn=2349067554729&text=Join&messageId=external1", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", }, { - Label: "Receive URL check", - URL: receiveURL, - ExpectedRespStatus: 200, - ExpectedRespBody: "no to parameter, ignored", + Label: "Receive URL check", + URL: receiveURL, + ExpectedRespStatus: 200, + ExpectedBodyContains: "no to parameter, ignored", }, { - Label: "Status URL check", - URL: statusURL, - ExpectedRespStatus: 200, - ExpectedRespBody: "no messageId parameter, ignored", + Label: "Status URL check", + URL: statusURL, + ExpectedRespStatus: 200, + ExpectedBodyContains: "no messageId parameter, ignored", }, { - Label: "Status delivered", - URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=delivered", - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"D"`, - ExpectedMsgStatus: courier.MsgDelivered, - ExpectedExternalID: "external1", + Label: "Status delivered", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=delivered", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, + ExpectedExternalID: "external1", }, { - Label: "Status expired", - URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=expired", - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"F"`, - ExpectedMsgStatus: courier.MsgFailed, - ExpectedExternalID: "external1", + Label: "Status expired", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=expired", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, + ExpectedExternalID: "external1", }, { - Label: "Status failed", - URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=failed", - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"F"`, - ExpectedMsgStatus: courier.MsgFailed, - ExpectedExternalID: "external1", + Label: "Status failed", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=failed", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, + ExpectedExternalID: "external1", }, { - Label: "Status accepted", - URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=accepted", - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"S"`, - ExpectedMsgStatus: courier.MsgSent, - ExpectedExternalID: "external1", + Label: "Status accepted", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=accepted", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, + ExpectedExternalID: "external1", }, { - Label: "Status buffered", - URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=buffered", - ExpectedRespStatus: 200, - ExpectedRespBody: `"status":"S"`, - ExpectedMsgStatus: courier.MsgSent, - ExpectedExternalID: "external1", + Label: "Status buffered", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=buffered", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, + ExpectedExternalID: "external1", }, { - Label: "Status unexpected", - URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=unexpected", - ExpectedRespStatus: 200, - ExpectedRespBody: "ignoring unknown status report", + Label: "Status unexpected", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=unexpected", + ExpectedRespStatus: 200, + ExpectedBodyContains: "ignoring unknown status report", }, } diff --git a/handlers/novo/novo_test.go b/handlers/novo/novo_test.go index dfb4b19e9..d93dba9f5 100644 --- a/handlers/novo/novo_test.go +++ b/handlers/novo/novo_test.go @@ -23,29 +23,29 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Headers: map[string]string{"Authorization": "sesame"}, - Data: "text=Msg&from=18686846481", - ExpectedRespStatus: 200, - ExpectedRespBody: "Message Accepted", - ExpectedMsgText: Sp("Msg"), - ExpectedURN: "tel:+18686846481", + Label: "Receive Valid", + URL: receiveURL, + Headers: map[string]string{"Authorization": "sesame"}, + Data: "text=Msg&from=18686846481", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Message Accepted", + ExpectedMsgText: Sp("Msg"), + ExpectedURN: "tel:+18686846481", }, { - Label: "Receive Missing Number", - URL: receiveURL, - Headers: map[string]string{"Authorization": "sesame"}, - Data: "text=Msg", - ExpectedRespStatus: 400, - ExpectedRespBody: "required field 'from'", + Label: "Receive Missing Number", + URL: receiveURL, + Headers: map[string]string{"Authorization": "sesame"}, + Data: "text=Msg", + ExpectedRespStatus: 400, + ExpectedBodyContains: "required field 'from'", }, { - Label: "Receive Missing Authorization", - URL: receiveURL, - Data: "text=Msg&from=18686846481", - ExpectedRespStatus: 401, - ExpectedRespBody: "invalid Authorization header", + Label: "Receive Missing Authorization", + URL: receiveURL, + Data: "text=Msg&from=18686846481", + ExpectedRespStatus: 401, + ExpectedBodyContains: "invalid Authorization header", }, } diff --git a/handlers/playmobile/playmobile_test.go b/handlers/playmobile/playmobile_test.go index cb8db7ae4..d4953ccec 100644 --- a/handlers/playmobile/playmobile_test.go +++ b/handlers/playmobile/playmobile_test.go @@ -75,50 +75,50 @@ var ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: validReceive, - ExpectedRespBody: "Accepted", - ExpectedRespStatus: 200, - ExpectedMsgText: Sp("SMS Response Accepted"), - ExpectedURN: "tel:+998999999999", + Label: "Receive Valid", + URL: receiveURL, + Data: validReceive, + ExpectedBodyContains: "Accepted", + ExpectedRespStatus: 200, + ExpectedMsgText: Sp("SMS Response Accepted"), + ExpectedURN: "tel:+998999999999", }, { - Label: "Receive Missing MSISDN", - URL: receiveURL, - Data: invalidReceive, - ExpectedRespBody: "missing required fields msidsn or id", - ExpectedRespStatus: 400, + Label: "Receive Missing MSISDN", + URL: receiveURL, + Data: invalidReceive, + ExpectedBodyContains: "missing required fields msidsn or id", + ExpectedRespStatus: 400, }, { - Label: "No Messages", - URL: receiveURL, - Data: noMessages, - ExpectedRespBody: "no messages, ignored", - ExpectedRespStatus: 200, + Label: "No Messages", + URL: receiveURL, + Data: noMessages, + ExpectedBodyContains: "no messages, ignored", + ExpectedRespStatus: 200, }, { - Label: "Invalid XML", - URL: receiveURL, - Data: invalidXML, - ExpectedRespBody: "", - ExpectedRespStatus: 405, + Label: "Invalid XML", + URL: receiveURL, + Data: invalidXML, + ExpectedBodyContains: "", + ExpectedRespStatus: 405, }, { - Label: "Receive With Prefix", - URL: receiveURL, - Data: receiveWithPrefix, - ExpectedRespBody: "Accepted", - ExpectedRespStatus: 200, - ExpectedMsgText: Sp("SMS Response Accepted"), - ExpectedURN: "tel:+998999999999", + Label: "Receive With Prefix", + URL: receiveURL, + Data: receiveWithPrefix, + ExpectedBodyContains: "Accepted", + ExpectedRespStatus: 200, + ExpectedMsgText: Sp("SMS Response Accepted"), + ExpectedURN: "tel:+998999999999", }, { - Label: "Receive With Prefix Only", - URL: receiveURL, - Data: receiveWithPrefixOnly, - ExpectedRespBody: "no text", - ExpectedRespStatus: 400, + Label: "Receive With Prefix Only", + URL: receiveURL, + Data: receiveWithPrefixOnly, + ExpectedBodyContains: "no text", + ExpectedRespStatus: 400, }, } diff --git a/handlers/plivo/plivo_test.go b/handlers/plivo/plivo_test.go index ec947c8aa..eaa940fa3 100644 --- a/handlers/plivo/plivo_test.go +++ b/handlers/plivo/plivo_test.go @@ -30,16 +30,16 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedBodyContains: "Message Accepted", ExpectedMsgText: Sp("Hello"), ExpectedURN: "tel:+60124361111", ExpectedExternalID: "abc1234"}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, - {Label: "Invalid Address Params", URL: receiveURL, Data: invalidAddress, ExpectedRespStatus: 400, ExpectedRespBody: "invalid to number [1515], expecting [2020]"}, - {Label: "Missing Params", URL: receiveURL, Data: missingParams, ExpectedRespStatus: 400, ExpectedRespBody: "Field validation for 'To' failed"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedBodyContains: "phone number supplied is not a number"}, + {Label: "Invalid Address Params", URL: receiveURL, Data: invalidAddress, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid to number [1515], expecting [2020]"}, + {Label: "Missing Params", URL: receiveURL, Data: missingParams, ExpectedRespStatus: 400, ExpectedBodyContains: "Field validation for 'To' failed"}, - {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered}, - {Label: "Sent Status", URL: statusURL, Data: validSentStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, ExpectedMsgStatus: courier.MsgSent}, - {Label: "Invalid Status Address", URL: statusURL, Data: invalidStatusAddress, ExpectedRespStatus: 400, ExpectedRespBody: "invalid to number [1515], expecting [2020]"}, - {Label: "Unkown Status", URL: statusURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedRespBody: `ignoring unknown status 'UNKNOWN'`}, + {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered}, + {Label: "Sent Status", URL: statusURL, Data: validSentStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"S"`, ExpectedMsgStatus: courier.MsgSent}, + {Label: "Invalid Status Address", URL: statusURL, Data: invalidStatusAddress, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid to number [1515], expecting [2020]"}, + {Label: "Unkown Status", URL: statusURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `ignoring unknown status 'UNKNOWN'`}, } func TestHandler(t *testing.T) { diff --git a/handlers/rocketchat/rocketchat_test.go b/handlers/rocketchat/rocketchat_test.go index 5517f06e9..fb37685c9 100644 --- a/handlers/rocketchat/rocketchat_test.go +++ b/handlers/rocketchat/rocketchat_test.go @@ -56,11 +56,11 @@ var testCases = []handlers.ChannelHandleTestCase{ Headers: map[string]string{ "Authorization": "Token 123456789", }, - Data: helloMsg, - ExpectedURN: "rocketchat:direct:john.doe#john.doe", - ExpectedMsgText: handlers.Sp("Hello World"), - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", + Data: helloMsg, + ExpectedURN: "rocketchat:direct:john.doe#john.doe", + ExpectedMsgText: handlers.Sp("Hello World"), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", }, { Label: "Receive Attachment Msg", @@ -68,11 +68,11 @@ var testCases = []handlers.ChannelHandleTestCase{ Headers: map[string]string{ "Authorization": "Token 123456789", }, - Data: attachmentMsg, - ExpectedURN: "rocketchat:livechat:onrMgdKbpX9Qqtvoi", - ExpectedAttachments: []string{"https://link.to/image.jpg"}, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", + Data: attachmentMsg, + ExpectedURN: "rocketchat:livechat:onrMgdKbpX9Qqtvoi", + ExpectedAttachments: []string{"https://link.to/image.jpg"}, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", }, { Label: "Don't Receive Empty Msg", @@ -80,9 +80,9 @@ var testCases = []handlers.ChannelHandleTestCase{ Headers: map[string]string{ "Authorization": "Token 123456789", }, - Data: emptyMsg, - ExpectedRespStatus: 400, - ExpectedRespBody: "no text or attachment", + Data: emptyMsg, + ExpectedRespStatus: 400, + ExpectedBodyContains: "no text or attachment", }, { Label: "Invalid Authorization", @@ -90,9 +90,9 @@ var testCases = []handlers.ChannelHandleTestCase{ Headers: map[string]string{ "Authorization": "123456789", }, - Data: emptyMsg, - ExpectedRespStatus: 401, - ExpectedRespBody: "invalid Authorization header", + Data: emptyMsg, + ExpectedRespStatus: 401, + ExpectedBodyContains: "invalid Authorization header", }, } diff --git a/handlers/shaqodoon/shaqodoon_test.go b/handlers/shaqodoon/shaqodoon_test.go index 33c24f9a8..5697982fd 100644 --- a/handlers/shaqodoon/shaqodoon_test.go +++ b/handlers/shaqodoon/shaqodoon_test.go @@ -27,20 +27,20 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, - {Label: "Receive Badly Escaped", URL: receiveBadlyEscaped, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Badly Escaped", URL: receiveBadlyEscaped, Data: "empty", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+252999999999"}, - {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp(""), ExpectedURN: "tel:+2349067554729"}, - {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "empty", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC)}, - {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "empty", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "empty", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC)}, - {Label: "Receive invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "field 'from' required"}, - {Label: "Receive No Sender", URL: receiveNoSender, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "field 'from' required"}, - {Label: "Receive Invalid Date", URL: receiveInvalidDate, Data: "empty", ExpectedRespStatus: 400, ExpectedRespBody: "invalid date format, must be RFC 3339"}, + {Label: "Receive invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedRespStatus: 400, ExpectedBodyContains: "phone number supplied is not a number"}, + {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedRespStatus: 400, ExpectedBodyContains: "field 'from' required"}, + {Label: "Receive No Sender", URL: receiveNoSender, Data: "empty", ExpectedRespStatus: 400, ExpectedBodyContains: "field 'from' required"}, + {Label: "Receive Invalid Date", URL: receiveInvalidDate, Data: "empty", ExpectedRespStatus: 400, ExpectedBodyContains: "invalid date format, must be RFC 3339"}, } func TestHandler(t *testing.T) { diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 96e633414..d0178558c 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -130,50 +130,50 @@ func setSendUrl(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, var handleTestCases = []ChannelHandleTestCase{ { - Label: "Receive Hello Msg", - URL: receiveURL, - Headers: map[string]string{}, - Data: helloMsg, - ExpectedURN: "slack:U0123ABCDEF", - ExpectedMsgText: Sp("Hello World!"), - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedExternalID: "Ev0PV52K21", + Label: "Receive Hello Msg", + URL: receiveURL, + Headers: map[string]string{}, + Data: helloMsg, + ExpectedURN: "slack:U0123ABCDEF", + ExpectedMsgText: Sp("Hello World!"), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedExternalID: "Ev0PV52K21", }, { - Label: "Receive image file", - URL: receiveURL, - Headers: map[string]string{}, - Data: imageFileMsg, - ExpectedAttachments: []string{"https://files.slack.com/files-pri/T03CN5KTA6S-F03GTH43SSF/download/batata.jpg?pub_secret=39fcf577f2"}, - ExpectedURN: "slack:U0123ABCDEF", - ExpectedMsgText: Sp(""), - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedExternalID: "Ev0PV52K21", + Label: "Receive image file", + URL: receiveURL, + Headers: map[string]string{}, + Data: imageFileMsg, + ExpectedAttachments: []string{"https://files.slack.com/files-pri/T03CN5KTA6S-F03GTH43SSF/download/batata.jpg?pub_secret=39fcf577f2"}, + ExpectedURN: "slack:U0123ABCDEF", + ExpectedMsgText: Sp(""), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedExternalID: "Ev0PV52K21", }, { - Label: "Receive audio file", - URL: receiveURL, - Headers: map[string]string{}, - Data: audioFileMsg, - ExpectedAttachments: []string{"https://files.slack.com/files-pri/T03CN5KTA6S-F03GWURCZL4/download/here_we_go_again.mp3?pub_secret=471020b300"}, - ExpectedURN: "slack:U0123ABCDEF", - ExpectedMsgText: Sp(""), - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedExternalID: "Ev0PV52K21", + Label: "Receive audio file", + URL: receiveURL, + Headers: map[string]string{}, + Data: audioFileMsg, + ExpectedAttachments: []string{"https://files.slack.com/files-pri/T03CN5KTA6S-F03GWURCZL4/download/here_we_go_again.mp3?pub_secret=471020b300"}, + ExpectedURN: "slack:U0123ABCDEF", + ExpectedMsgText: Sp(""), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedExternalID: "Ev0PV52K21", }, { - Label: "Receive video file (not allowed)", - URL: receiveURL, - Headers: map[string]string{}, - Data: videoFileMsg, - ExpectedURN: "slack:U0123ABCDEF", - ExpectedMsgText: Sp(""), - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedExternalID: "Ev0PV52K21", + Label: "Receive video file (not allowed)", + URL: receiveURL, + Headers: map[string]string{}, + Data: videoFileMsg, + ExpectedURN: "slack:U0123ABCDEF", + ExpectedMsgText: Sp(""), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedExternalID: "Ev0PV52K21", }, } @@ -266,9 +266,9 @@ func TestSendFiles(t *testing.T) { func TestVerification(t *testing.T) { RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ {Label: "Valid token", URL: receiveURL, ExpectedRespStatus: 200, - Data: `{"token":"one-long-verification-token","challenge":"challenge123","type":"url_verification"}`, - Headers: map[string]string{"content-type": "text/plain"}, - ExpectedRespBody: "challenge123", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, + Data: `{"token":"one-long-verification-token","challenge":"challenge123","type":"url_verification"}`, + Headers: map[string]string{"content-type": "text/plain"}, + ExpectedBodyContains: "challenge123", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, }, {Label: "Invalid token", URL: receiveURL, ExpectedRespStatus: 403, Data: `{"token":"abc321","challenge":"challenge123","type":"url_verification"}`, diff --git a/handlers/smscentral/smscentral_test.go b/handlers/smscentral/smscentral_test.go index 5ae501b73..58e803f4b 100644 --- a/handlers/smscentral/smscentral_test.go +++ b/handlers/smscentral/smscentral_test.go @@ -19,43 +19,43 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: receiveURL, - Data: "mobile=%2B2349067554729&message=Join", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", + Label: "Receive Valid Message", + URL: receiveURL, + Data: "mobile=%2B2349067554729&message=Join", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", }, { - Label: "Receive No Message", - URL: receiveURL, - Data: "mobile=%2B2349067554729", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp(""), - ExpectedURN: "tel:+2349067554729", + Label: "Receive No Message", + URL: receiveURL, + Data: "mobile=%2B2349067554729", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedURN: "tel:+2349067554729", }, { - Label: "Receive invalid URN", - URL: receiveURL, - Data: "mobile=MTN&message=Join", - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Receive invalid URN", + URL: receiveURL, + Data: "mobile=MTN&message=Join", + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, { - Label: "Receive No Params", - URL: receiveURL, - Data: "none", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'mobile' required", + Label: "Receive No Params", + URL: receiveURL, + Data: "none", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'mobile' required", }, { - Label: "Receive No Sender", - URL: receiveURL, - Data: "message=Join", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'mobile' required", + Label: "Receive No Sender", + URL: receiveURL, + Data: "message=Join", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'mobile' required", }, } diff --git a/handlers/start/start_test.go b/handlers/start/start_test.go index 3f41dc83b..746e7f052 100644 --- a/handlers/start/start_test.go +++ b/handlers/start/start_test.go @@ -74,77 +74,77 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: validReceive, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Hello World"), - ExpectedURN: "tel:+250788123123", - ExpectedDate: time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC), + Label: "Receive Valid", + URL: receiveURL, + Data: validReceive, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: "tel:+250788123123", + ExpectedDate: time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC), }, { - Label: "Receive Valid Encoded", - URL: receiveURL, - Data: validReceiveEncoded, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Кохання"), - ExpectedURN: "tel:+380501529999", - ExpectedDate: time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC), + Label: "Receive Valid Encoded", + URL: receiveURL, + Data: validReceiveEncoded, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Кохання"), + ExpectedURN: "tel:+380501529999", + ExpectedDate: time.Date(2015, 12, 18, 15, 02, 54, 0, time.UTC), }, { - Label: "Receive Valid with empty Text", - URL: receiveURL, - Data: validReceiveEmptyText, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp(""), - ExpectedURN: "tel:+250788123123", + Label: "Receive Valid with empty Text", + URL: receiveURL, + Data: validReceiveEmptyText, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedURN: "tel:+250788123123", }, { - Label: "Receive Valid missing body", - URL: receiveURL, - Data: validMissingBody, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp(""), - ExpectedURN: "tel:+250788123123", + Label: "Receive Valid missing body", + URL: receiveURL, + Data: validMissingBody, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedURN: "tel:+250788123123", }, { - Label: "Receive invalidURN", - URL: receiveURL, - Data: invalidURNReceive, - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Receive invalidURN", + URL: receiveURL, + Data: invalidURNReceive, + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, { - Label: "Receive missing Request ID", - URL: receiveURL, - Data: missingRequestID, - ExpectedRespStatus: 400, - ExpectedRespBody: "Error", + Label: "Receive missing Request ID", + URL: receiveURL, + Data: missingRequestID, + ExpectedRespStatus: 400, + ExpectedBodyContains: "Error", }, { - Label: "Receive missing From", - URL: receiveURL, - Data: missingFrom, - ExpectedRespStatus: 400, - ExpectedRespBody: "Error", + Label: "Receive missing From", + URL: receiveURL, + Data: missingFrom, + ExpectedRespStatus: 400, + ExpectedBodyContains: "Error", }, { - Label: "Receive missing To", - URL: receiveURL, - Data: missingTo, - ExpectedRespStatus: 400, - ExpectedRespBody: "Error", + Label: "Receive missing To", + URL: receiveURL, + Data: missingTo, + ExpectedRespStatus: 400, + ExpectedBodyContains: "Error", }, { - Label: "Invalid XML", - URL: receiveURL, - Data: "empty", - ExpectedRespStatus: 400, - ExpectedRespBody: "Error", + Label: "Invalid XML", + URL: receiveURL, + Data: "empty", + ExpectedRespStatus: 400, + ExpectedBodyContains: "Error", }, } diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index 238c6c4a4..19846a8cb 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -454,180 +454,180 @@ var contactMsg = ` var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: helloMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), - ExpectedMsgText: Sp("Hello World"), - ExpectedURN: "telegram:3527065#nicpottier", - ExpectedExternalID: "41", - ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + Label: "Receive Valid Message", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: helloMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedExternalID: "41", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), }, { - Label: "Receive Start Message", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: startMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), - ExpectedEvent: courier.NewConversation, - ExpectedURN: "telegram:3527065#nicpottier", - ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + Label: "Receive Start Message", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: startMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedEvent: courier.NewConversation, + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), }, { - Label: "Receive No Params", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: emptyMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Ignoring", + Label: "Receive No Params", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: emptyMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Ignoring", }, { - Label: "Receive Invalid JSON", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: "foo", - ExpectedRespStatus: 400, - ExpectedRespBody: "unable to parse", + Label: "Receive Invalid JSON", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: "foo", + ExpectedRespStatus: 400, + ExpectedBodyContains: "unable to parse", }, { - Label: "Receive Sticker", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: stickerMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), - ExpectedMsgText: Sp(""), - ExpectedAttachments: []string{"/file/bota123/sticker.jpg"}, - ExpectedURN: "telegram:3527065", - ExpectedExternalID: "44", - ExpectedDate: time.Date(2016, 1, 30, 2, 07, 48, 0, time.UTC), + Label: "Receive Sticker", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: stickerMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"/file/bota123/sticker.jpg"}, + ExpectedURN: "telegram:3527065", + ExpectedExternalID: "44", + ExpectedDate: time.Date(2016, 1, 30, 2, 07, 48, 0, time.UTC), }, { - Label: "Receive Photo", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: photoMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), - ExpectedMsgText: Sp("Photo Caption"), - ExpectedAttachments: []string{"/file/bota123/photo.jpg"}, - ExpectedURN: "telegram:3527065#nicpottier", - ExpectedExternalID: "85", - ExpectedDate: time.Date(2017, 5, 3, 20, 28, 38, 0, time.UTC), + Label: "Receive Photo", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: photoMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp("Photo Caption"), + ExpectedAttachments: []string{"/file/bota123/photo.jpg"}, + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedExternalID: "85", + ExpectedDate: time.Date(2017, 5, 3, 20, 28, 38, 0, time.UTC), }, { - Label: "Receive Video", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: videoMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), - ExpectedMsgText: Sp(""), - ExpectedAttachments: []string{"/file/bota123/video.jpg"}, - ExpectedURN: "telegram:3527065#nicpottier", - ExpectedExternalID: "86", - ExpectedDate: time.Date(2017, 5, 3, 20, 29, 24, 0, time.UTC), + Label: "Receive Video", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: videoMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"/file/bota123/video.jpg"}, + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedExternalID: "86", + ExpectedDate: time.Date(2017, 5, 3, 20, 29, 24, 0, time.UTC), }, { - Label: "Receive Voice", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: voiceMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), - ExpectedMsgText: Sp(""), - ExpectedAttachments: []string{"/file/bota123/voice.mp4"}, - ExpectedURN: "telegram:3527065#nicpottier", - ExpectedExternalID: "91", - ExpectedDate: time.Date(2017, 5, 3, 20, 50, 46, 0, time.UTC), + Label: "Receive Voice", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: voiceMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"/file/bota123/voice.mp4"}, + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedExternalID: "91", + ExpectedDate: time.Date(2017, 5, 3, 20, 50, 46, 0, time.UTC), }, { - Label: "Receive Document", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: documentMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), - ExpectedMsgText: Sp(""), - ExpectedAttachments: []string{"/file/bota123/document.xls"}, - ExpectedURN: "telegram:3527065#nicpottier", - ExpectedExternalID: "92", - ExpectedDate: time.Date(2017, 5, 3, 20, 58, 20, 0, time.UTC), + Label: "Receive Document", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: documentMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"/file/bota123/document.xls"}, + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedExternalID: "92", + ExpectedDate: time.Date(2017, 5, 3, 20, 58, 20, 0, time.UTC), }, { - Label: "Receive Location", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: locationMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), - ExpectedMsgText: Sp("-2.890287,-79.004333"), - ExpectedAttachments: []string{"geo:-2.890287,-79.004333"}, - ExpectedURN: "telegram:3527065#nicpottier", - ExpectedExternalID: "94", - ExpectedDate: time.Date(2017, 5, 3, 21, 00, 44, 0, time.UTC), + Label: "Receive Location", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: locationMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp("-2.890287,-79.004333"), + ExpectedAttachments: []string{"geo:-2.890287,-79.004333"}, + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedExternalID: "94", + ExpectedDate: time.Date(2017, 5, 3, 21, 00, 44, 0, time.UTC), }, { - Label: "Receive Venue", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: venueMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), - ExpectedMsgText: Sp("Cuenca, Provincia del Azuay"), - ExpectedAttachments: []string{"geo:-2.898944,-79.006835"}, - ExpectedURN: "telegram:3527065#nicpottier", - ExpectedExternalID: "95", - ExpectedDate: time.Date(2017, 5, 3, 21, 05, 20, 0, time.UTC), + Label: "Receive Venue", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: venueMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp("Cuenca, Provincia del Azuay"), + ExpectedAttachments: []string{"geo:-2.898944,-79.006835"}, + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedExternalID: "95", + ExpectedDate: time.Date(2017, 5, 3, 21, 05, 20, 0, time.UTC), }, { - Label: "Receive Contact", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: contactMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedContactName: Sp("Nic Pottier"), - ExpectedMsgText: Sp("Adolf Taxi (0788531373)"), - ExpectedURN: "telegram:3527065#nicpottier", - ExpectedExternalID: "96", - ExpectedDate: time.Date(2017, 5, 3, 21, 9, 15, 0, time.UTC), + Label: "Receive Contact", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: contactMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedContactName: Sp("Nic Pottier"), + ExpectedMsgText: Sp("Adolf Taxi (0788531373)"), + ExpectedURN: "telegram:3527065#nicpottier", + ExpectedExternalID: "96", + ExpectedDate: time.Date(2017, 5, 3, 21, 9, 15, 0, time.UTC), }, { - Label: "Receive Empty", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: emptyMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Ignoring", + Label: "Receive Empty", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: emptyMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Ignoring", }, { - Label: "Receive Invalid FileID", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: invalidFileID, - ExpectedRespStatus: 200, - ExpectedRespBody: "unable to resolve file", + Label: "Receive Invalid FileID", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: invalidFileID, + ExpectedRespStatus: 200, + ExpectedBodyContains: "unable to resolve file", }, { - Label: "Receive NoOk FileID", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: noOkFile, - ExpectedRespStatus: 200, - ExpectedRespBody: "no 'ok' in response", + Label: "Receive NoOk FileID", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: noOkFile, + ExpectedRespStatus: 200, + ExpectedBodyContains: "no 'ok' in response", }, { - Label: "Receive NotOk FileID", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: notOkFile, - ExpectedRespStatus: 200, - ExpectedRespBody: "not present", + Label: "Receive NotOk FileID", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: notOkFile, + ExpectedRespStatus: 200, + ExpectedBodyContains: "not present", }, { - Label: "Receive No FileID", - URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", - Data: noFile, - ExpectedRespStatus: 200, - ExpectedRespBody: "result.file_path", + Label: "Receive No FileID", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: noFile, + ExpectedRespStatus: 200, + ExpectedBodyContains: "result.file_path", }, } diff --git a/handlers/telesom/telesom_test.go b/handlers/telesom/telesom_test.go index c56cf095f..0a5a67404 100644 --- a/handlers/telesom/telesom_test.go +++ b/handlers/telesom/telesom_test.go @@ -17,60 +17,60 @@ var testChannels = []courier.Channel{ var handleTestCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Message", - URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?mobile=%2B2349067554729&msg=Join", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", + Label: "Receive Valid Message", + URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?mobile=%2B2349067554729&msg=Join", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", }, { - Label: "Invalid URN", - URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?mobile=MTN&msg=Join", - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Invalid URN", + URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?mobile=MTN&msg=Join", + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, { - Label: "Receive No Params", - URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'mobile' required", + Label: "Receive No Params", + URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'mobile' required", }, { - Label: "Receive No Sender", - URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?msg=Join", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'mobile' required", + Label: "Receive No Sender", + URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?msg=Join", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'mobile' required", }, { - Label: "Receive Valid Message", - URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", - Data: "mobile=%2B2349067554729&msg=Join", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("Join"), - ExpectedURN: "tel:+2349067554729", + Label: "Receive Valid Message", + URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + Data: "mobile=%2B2349067554729&msg=Join", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", }, { - Label: "Invalid URN", - URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", - Data: "mobile=MTN&msg=Join", - ExpectedRespStatus: 400, - ExpectedRespBody: "phone number supplied is not a number", + Label: "Invalid URN", + URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + Data: "mobile=MTN&msg=Join", + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", }, { - Label: "Receive No Params", - URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", - Data: "empty", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'mobile' required", + Label: "Receive No Params", + URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + Data: "empty", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'mobile' required", }, { - Label: "Receive No Sender", - URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", - Data: "msg=Join", - ExpectedRespStatus: 400, - ExpectedRespBody: "field 'mobile' required", + Label: "Receive No Sender", + URL: "/c/ts/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + Data: "msg=Join", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'mobile' required", }, } diff --git a/handlers/test.go b/handlers/test.go index 0c9656c79..1d009b0a8 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -38,19 +38,19 @@ type ChannelHandleTestCase struct { Headers map[string]string MultipartForm map[string]string - ExpectedRespStatus int - ExpectedRespBody string - ExpectedContactName *string - ExpectedMsgText *string - ExpectedURN urns.URN - ExpectedURNAuth string - ExpectedAttachments []string - ExpectedDate time.Time - ExpectedMsgStatus courier.MsgStatusValue - ExpectedExternalID string - ExpectedMsgID int64 - ExpectedEvent courier.ChannelEventType - ExpectedEventExtra map[string]interface{} + ExpectedRespStatus int + ExpectedBodyContains string + ExpectedContactName *string + ExpectedMsgText *string + ExpectedURN urns.URN + ExpectedURNAuth string + ExpectedAttachments []string + ExpectedDate time.Time + ExpectedMsgStatus courier.MsgStatusValue + ExpectedExternalID string + ExpectedMsgID int64 + ExpectedEvent courier.ChannelEventType + ExpectedEventExtra map[string]interface{} } // MockedRequest is a fake HTTP request @@ -67,7 +67,7 @@ func (m MockedRequest) Matches(r *http.Request, body []byte) bool { } // utility method to make a request to a handler URL -func testHandlerRequest(tb testing.TB, s courier.Server, path string, headers map[string]string, data string, multipartFormFields map[string]string, expectedStatus int, expectedBody string, requestPrepFunc RequestPrepFunc) string { +func testHandlerRequest(tb testing.TB, s courier.Server, path string, headers map[string]string, data string, multipartFormFields map[string]string, expectedStatus int, expectedBodyContains string, requestPrepFunc RequestPrepFunc) string { var req *http.Request var err error url := fmt.Sprintf("https://%s%s", s.Config().Domain, path) @@ -118,10 +118,10 @@ func testHandlerRequest(tb testing.TB, s courier.Server, path string, headers ma body := rr.Body.String() - require.Equal(tb, expectedStatus, rr.Code, fmt.Sprintf("incorrect status code with response: %s", body)) + assert.Equal(tb, expectedStatus, rr.Code, "status code mismatch") - if expectedBody != "" { - assert.Contains(tb, body, expectedBody) + if expectedBodyContains != "" { + assert.Contains(tb, body, expectedBodyContains) } return body @@ -158,7 +158,7 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri mb.Reset() - testHandlerRequest(t, s, tc.URL, tc.Headers, tc.Data, tc.MultipartForm, tc.ExpectedRespStatus, tc.ExpectedRespBody, tc.PrepRequest) + testHandlerRequest(t, s, tc.URL, tc.Headers, tc.Data, tc.MultipartForm, tc.ExpectedRespStatus, tc.ExpectedBodyContains, tc.PrepRequest) if tc.ExpectedMsgText != nil || tc.ExpectedAttachments != nil { require.Len(mb.WrittenMsgs(), 1, "expected a msg to be written") diff --git a/handlers/thinq/thinq_test.go b/handlers/thinq/thinq_test.go index b68c3512a..153bce79a 100644 --- a/handlers/thinq/thinq_test.go +++ b/handlers/thinq/thinq_test.go @@ -26,63 +26,63 @@ var testJpgBase64 = base64.StdEncoding.EncodeToString(test.ReadFile("../../test/ var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: "message=hello+world&from=2065551234&type=sms&to=2065551212", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("hello world"), - ExpectedURN: "tel:+12065551234", + Label: "Receive Valid", + URL: receiveURL, + Data: "message=hello+world&from=2065551234&type=sms&to=2065551212", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("hello world"), + ExpectedURN: "tel:+12065551234", }, { - Label: "Receive No Params", - URL: receiveURL, - Data: " ", - ExpectedRespStatus: 400, - ExpectedRespBody: `'From' failed on the 'required'`, + Label: "Receive No Params", + URL: receiveURL, + Data: " ", + ExpectedRespStatus: 400, + ExpectedBodyContains: `'From' failed on the 'required'`, }, { - Label: "Receive attachment as URL", - URL: receiveURL, - Data: "message=http://foo.bar/foo.png&from=2065551234&type=mms&to=2065551212", - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedURN: "tel:+12065551234", - ExpectedAttachments: []string{"http://foo.bar/foo.png"}, + Label: "Receive attachment as URL", + URL: receiveURL, + Data: "message=http://foo.bar/foo.png&from=2065551234&type=mms&to=2065551212", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedURN: "tel:+12065551234", + ExpectedAttachments: []string{"http://foo.bar/foo.png"}, }, { - Label: "Receive attachment as base64", - URL: receiveURL, - Data: fmt.Sprintf("message=%s&from=2065551234&type=mms&to=2065551212", url.QueryEscape(testJpgBase64)), - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedURN: "tel:+12065551234", - ExpectedAttachments: []string{"data:" + testJpgBase64}, + Label: "Receive attachment as base64", + URL: receiveURL, + Data: fmt.Sprintf("message=%s&from=2065551234&type=mms&to=2065551212", url.QueryEscape(testJpgBase64)), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedURN: "tel:+12065551234", + ExpectedAttachments: []string{"data:" + testJpgBase64}, }, { - Label: "Status Valid", - URL: statusURL, - Data: "guid=1234&status=DELIVRD", - ExpectedRespStatus: 200, - ExpectedExternalID: "1234", - ExpectedRespBody: `"status":"D"`, - ExpectedMsgStatus: courier.MsgDelivered, + Label: "Status Valid", + URL: statusURL, + Data: "guid=1234&status=DELIVRD", + ExpectedRespStatus: 200, + ExpectedExternalID: "1234", + ExpectedBodyContains: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, }, { - Label: "Status Invalid", - URL: statusURL, - Data: "guid=1234&status=UN", - ExpectedRespStatus: 400, - ExpectedExternalID: "1234", - ExpectedRespBody: `"unknown status: 'UN'"`, + Label: "Status Invalid", + URL: statusURL, + Data: "guid=1234&status=UN", + ExpectedRespStatus: 400, + ExpectedExternalID: "1234", + ExpectedBodyContains: `"unknown status: 'UN'"`, }, { - Label: "Status Missing GUID", - URL: statusURL, - Data: "status=DELIVRD", - ExpectedRespStatus: 400, - ExpectedExternalID: "1234", - ExpectedRespBody: `'GUID' failed on the 'required' tag`, + Label: "Status Missing GUID", + URL: statusURL, + Data: "status=DELIVRD", + ExpectedRespStatus: 400, + ExpectedExternalID: "1234", + ExpectedBodyContains: `'GUID' failed on the 'required' tag`, }, } diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index 7a69181a8..8031fb5d8 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -77,160 +77,160 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: receiveValid, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Valid", URL: receiveURL, Data: receiveValid, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Receive Button Ignored", URL: receiveURL, Data: receiveButtonIgnored, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Button Ignored", URL: receiveURL, Data: receiveButtonIgnored, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Receive Invalid Signature", URL: receiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedRespBody: "invalid request signature", + {Label: "Receive Invalid Signature", URL: receiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid request signature", PrepRequest: addInvalidSignature}, - {Label: "Receive Missing Signature", URL: receiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedRespBody: "missing request signature"}, - {Label: "Receive No Params", URL: receiveURL, Data: " ", ExpectedRespStatus: 400, ExpectedRespBody: "field 'messagesid' required", + {Label: "Receive Missing Signature", URL: receiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedBodyContains: "missing request signature"}, + {Label: "Receive No Params", URL: receiveURL, Data: " ", ExpectedRespStatus: 400, ExpectedBodyContains: "field 'messagesid' required", PrepRequest: addValidSignature}, - {Label: "Receive Media", URL: receiveURL, Data: receiveMedia, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Media", URL: receiveURL, Data: receiveMedia, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Media With Msg", URL: receiveURL, Data: receiveMediaWithMsg, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Media With Msg", URL: receiveURL, Data: receiveMediaWithMsg, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Base64", URL: receiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Base64", URL: receiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status Stop contact", URL: statusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", + {Label: "Status Stop contact", URL: statusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", PrepRequest: addValidSignature}, - {Label: "Status No Params", URL: statusURL, Data: " ", ExpectedRespStatus: 200, ExpectedRespBody: "no msg status, ignoring", + {Label: "Status No Params", URL: statusURL, Data: " ", ExpectedRespStatus: 200, ExpectedBodyContains: "no msg status, ignoring", PrepRequest: addValidSignature}, - {Label: "Status Invalid Status", URL: statusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status 'huh'", + {Label: "Status Invalid Status", URL: statusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedBodyContains: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: statusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status Valid", URL: statusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status Read", URL: statusURL, Data: statusRead, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status Read", URL: statusURL, Data: statusRead, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status ID Valid", URL: statusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedMsgID: 12345, + {Label: "Status ID Valid", URL: statusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: statusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status ID Invalid", URL: statusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } var tmsTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: tmsReceiveURL, Data: receiveValid, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Valid", URL: tmsReceiveURL, Data: receiveValid, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Receive TMS extra", URL: tmsReceiveURL, Data: tmsReceiveExtra, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive TMS extra", URL: tmsReceiveURL, Data: tmsReceiveExtra, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("John Cruz"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMbbf29aeb9d380ce2a1c0ae4635ff9dab", PrepRequest: addValidSignature}, - {Label: "Receive Invalid Signature", URL: tmsReceiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedRespBody: "invalid request signature", + {Label: "Receive Invalid Signature", URL: tmsReceiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid request signature", PrepRequest: addInvalidSignature}, - {Label: "Receive Missing Signature", URL: tmsReceiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedRespBody: "missing request signature"}, - {Label: "Receive No Params", URL: tmsReceiveURL, Data: " ", ExpectedRespStatus: 400, ExpectedRespBody: "field 'messagesid' required", + {Label: "Receive Missing Signature", URL: tmsReceiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedBodyContains: "missing request signature"}, + {Label: "Receive No Params", URL: tmsReceiveURL, Data: " ", ExpectedRespStatus: 400, ExpectedBodyContains: "field 'messagesid' required", PrepRequest: addValidSignature}, - {Label: "Receive Media", URL: tmsReceiveURL, Data: receiveMedia, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Media", URL: tmsReceiveURL, Data: receiveMedia, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Media With Msg", URL: tmsReceiveURL, Data: receiveMediaWithMsg, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Media With Msg", URL: tmsReceiveURL, Data: receiveMediaWithMsg, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Base64", URL: tmsReceiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Base64", URL: tmsReceiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status Stop contact", URL: tmsStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", + {Label: "Status Stop contact", URL: tmsStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", PrepRequest: addValidSignature}, - {Label: "Status TMS extra", URL: tmsStatusURL, Data: tmsStatusExtra, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"S"`, ExpectedMsgStatus: courier.MsgSent, + {Label: "Status TMS extra", URL: tmsStatusURL, Data: tmsStatusExtra, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"S"`, ExpectedMsgStatus: courier.MsgSent, ExpectedExternalID: "SM0b6e2697aae04182a9f5b5c7a8994c7f", PrepRequest: addValidSignature}, - {Label: "Status No Params", URL: tmsStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedRespBody: "no msg status, ignoring", + {Label: "Status No Params", URL: tmsStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedBodyContains: "no msg status, ignoring", PrepRequest: addValidSignature}, - {Label: "Status Invalid Status", URL: tmsStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status 'huh'", + {Label: "Status Invalid Status", URL: tmsStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedBodyContains: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: tmsStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status Valid", URL: tmsStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status ID Valid", URL: tmsStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedMsgID: 12345, + {Label: "Status ID Valid", URL: tmsStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: tmsStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status ID Invalid", URL: tmsStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } var twTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: twReceiveURL, Data: receiveValid, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Valid", URL: twReceiveURL, Data: receiveValid, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, {Label: "Receive Forwarded Valid", URL: twReceiveURL, Data: receiveValid, Headers: map[string]string{forwardedPathHeader: "/handlers/twilio/receive/8eb23e93-5ecb-45ba-b726-3b064e0c56ab"}, - ExpectedRespStatus: 200, ExpectedRespBody: "", + ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addForwardSignature}, - {Label: "Receive Invalid Signature", URL: twReceiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedRespBody: "invalid request signature", + {Label: "Receive Invalid Signature", URL: twReceiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid request signature", PrepRequest: addInvalidSignature}, - {Label: "Receive Missing Signature", URL: twReceiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedRespBody: "missing request signature"}, - {Label: "Receive No Params", URL: twReceiveURL, Data: " ", ExpectedRespStatus: 400, ExpectedRespBody: "field 'messagesid' required", + {Label: "Receive Missing Signature", URL: twReceiveURL, Data: receiveValid, ExpectedRespStatus: 400, ExpectedBodyContains: "missing request signature"}, + {Label: "Receive No Params", URL: twReceiveURL, Data: " ", ExpectedRespStatus: 400, ExpectedBodyContains: "field 'messagesid' required", PrepRequest: addValidSignature}, - {Label: "Receive Media", URL: twReceiveURL, Data: receiveMedia, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Media", URL: twReceiveURL, Data: receiveMedia, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Media With Msg", URL: twReceiveURL, Data: receiveMediaWithMsg, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Media With Msg", URL: twReceiveURL, Data: receiveMediaWithMsg, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}, PrepRequest: addValidSignature}, - {Label: "Receive Base64", URL: twReceiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Base64", URL: twReceiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status Stop contact", URL: twStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", + {Label: "Status Stop contact", URL: twStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", PrepRequest: addValidSignature}, - {Label: "Status No Params", URL: twStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedRespBody: "no msg status, ignoring", + {Label: "Status No Params", URL: twStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedBodyContains: "no msg status, ignoring", PrepRequest: addValidSignature}, - {Label: "Status Invalid Status", URL: twStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status 'huh'", + {Label: "Status Invalid Status", URL: twStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedBodyContains: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: twStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status Valid", URL: twStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status ID Valid", URL: twStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedMsgID: 12345, + {Label: "Status ID Valid", URL: twStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: twStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status ID Invalid", URL: twStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } var swTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: swReceiveURL, Data: receiveValid, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Valid", URL: swReceiveURL, Data: receiveValid, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, - {Label: "Receive No Params", URL: swReceiveURL, Data: " ", ExpectedRespStatus: 400, ExpectedRespBody: "field 'messagesid' required"}, - {Label: "Receive Media", URL: swReceiveURL, Data: receiveMedia, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive No Params", URL: swReceiveURL, Data: " ", ExpectedRespStatus: 400, ExpectedBodyContains: "field 'messagesid' required"}, + {Label: "Receive Media", URL: swReceiveURL, Data: receiveMedia, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}}, - {Label: "Receive Media With Msg", URL: swReceiveURL, Data: receiveMediaWithMsg, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Media With Msg", URL: swReceiveURL, Data: receiveMediaWithMsg, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}}, - {Label: "Receive Base64", URL: swReceiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Base64", URL: swReceiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, - {Label: "Status Stop contact", URL: swStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", + {Label: "Status Stop contact", URL: swStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", PrepRequest: addValidSignature}, - {Label: "Status No Params", URL: swStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedRespBody: "no msg status, ignoring"}, - {Label: "Status Invalid Status", URL: swStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status 'huh'"}, - {Label: "Status Valid", URL: swStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, - {Label: "Status ID Valid", URL: swStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedMsgID: 12345}, - {Label: "Status ID Invalid", URL: swStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, + {Label: "Status No Params", URL: swStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedBodyContains: "no msg status, ignoring"}, + {Label: "Status Invalid Status", URL: swStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedBodyContains: "unknown status 'huh'"}, + {Label: "Status Valid", URL: swStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, + {Label: "Status ID Valid", URL: swStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedMsgID: 12345}, + {Label: "Status ID Invalid", URL: swStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, } var waTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: waReceiveValid, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Valid", URL: receiveURL, Data: waReceiveValid, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "whatsapp:14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } var twaTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: twaReceiveURL, Data: waReceiveValid, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Valid", URL: twaReceiveURL, Data: waReceiveValid, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "whatsapp:14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Receive Valid", URL: twaReceiveURL, Data: waReceiveButtonValid, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Valid", URL: twaReceiveURL, Data: waReceiveButtonValid, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Confirm"), ExpectedURN: "whatsapp:14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Receive Prefixless URN", URL: twaReceiveURL, Data: waReceivePrefixlessURN, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Prefixless URN", URL: twaReceiveURL, Data: waReceivePrefixlessURN, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Msg"), ExpectedURN: "whatsapp:14133881111", ExpectedExternalID: "SM681a1f26d9ec591431ce406e8f399525", PrepRequest: addValidSignature}, - {Label: "Status No Params", URL: twaStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedRespBody: "no msg status, ignoring", + {Label: "Status No Params", URL: twaStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedBodyContains: "no msg status, ignoring", PrepRequest: addValidSignature}, - {Label: "Status Invalid Status", URL: twaStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedRespBody: "unknown status 'huh'", + {Label: "Status Invalid Status", URL: twaStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedBodyContains: "unknown status 'huh'", PrepRequest: addValidSignature}, - {Label: "Status Valid", URL: twaStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status Valid", URL: twaStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status ID Valid", URL: twaStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedMsgID: 12345, + {Label: "Status ID Valid", URL: twaStatusIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedMsgID: 12345, PrepRequest: addValidSignature}, - {Label: "Status ID Invalid", URL: twaStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", + {Label: "Status ID Invalid", URL: twaStatusInvalidIDURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, } diff --git a/handlers/twitter/twitter_test.go b/handlers/twitter/twitter_test.go index b6a703b79..cb06ee4e3 100644 --- a/handlers/twitter/twitter_test.go +++ b/handlers/twitter/twitter_test.go @@ -167,17 +167,17 @@ var attachment = `{ var notJSON = `blargh` var testCases = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: helloMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Message", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: helloMsg, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedContactName: Sp("Nicolas Pottier"), ExpectedURN: "twitterid:272953809#nicpottier", ExpectedMsgText: Sp("Hello World & good wishes."), ExpectedExternalID: "958501034212564996", ExpectedDate: time.Date(2018, 1, 31, 0, 43, 49, 301000000, time.UTC)}, - {Label: "Receive Attachment", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: attachment, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Attachment", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: attachment, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("Hello"), ExpectedAttachments: []string{"https://image.foo.com/image.jpg"}, ExpectedURN: "twitterid:272953809#nicpottier", ExpectedExternalID: "958501034212564996", ExpectedDate: time.Date(2018, 1, 31, 0, 43, 49, 301000000, time.UTC)}, - {Label: "Not JSON", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "Error"}, - {Label: "Invalid Twitter handle", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidTwitterHandle, ExpectedRespStatus: 400, ExpectedRespBody: "invalid twitter handle"}, - {Label: "Invalid Twitter ID", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidTwitterID, ExpectedRespStatus: 400, ExpectedRespBody: "invalid twitter id"}, + {Label: "Not JSON", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: notJSON, ExpectedRespStatus: 400, ExpectedBodyContains: "Error"}, + {Label: "Invalid Twitter handle", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidTwitterHandle, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid twitter handle"}, + {Label: "Invalid Twitter ID", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", Data: invalidTwitterID, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid twitter id"}, - {Label: "Webhook Verification", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?crc_token=test+token", ExpectedRespStatus: 200, ExpectedRespBody: "sha256=O5hJl2njQRIa4vsumZ+3oom9ECR5m3aQLRZkPoYelp0="}, - {Label: "Webhook Verification Error", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", ExpectedRespStatus: 400, ExpectedRespBody: "missing required 'crc_token'"}, + {Label: "Webhook Verification", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive?crc_token=test+token", ExpectedRespStatus: 200, ExpectedBodyContains: "sha256=O5hJl2njQRIa4vsumZ+3oom9ECR5m3aQLRZkPoYelp0="}, + {Label: "Webhook Verification Error", URL: "/c/twt/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", ExpectedRespStatus: 400, ExpectedBodyContains: "missing required 'crc_token'"}, } func TestHandler(t *testing.T) { diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index af6ec39d3..61ae1be45 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -481,66 +481,66 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("incoming msg"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", PrepRequest: addValidSignature}, - {Label: "Receive invalid signature", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 400, ExpectedRespBody: "invalid request signature", + {Label: "Receive invalid signature", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid request signature", PrepRequest: addInvalidSignature}, - {Label: "Receive invalid JSON", URL: receiveURL, Data: invalidJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON", + {Label: "Receive invalid JSON", URL: receiveURL, Data: invalidJSON, ExpectedRespStatus: 400, ExpectedBodyContains: "unable to parse request JSON", PrepRequest: addValidSignature}, - {Label: "Receive invalid URN", URL: receiveURL, Data: invalidURNMsg, ExpectedRespStatus: 400, ExpectedRespBody: "invalid viber id", + {Label: "Receive invalid URN", URL: receiveURL, Data: invalidURNMsg, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid viber id", PrepRequest: addValidSignature}, - {Label: "Receive invalid Message Type", URL: receiveURL, Data: receiveInvalidMessageType, ExpectedRespStatus: 400, ExpectedRespBody: "unknown message type", + {Label: "Receive invalid Message Type", URL: receiveURL, Data: receiveInvalidMessageType, ExpectedRespStatus: 400, ExpectedBodyContains: "unknown message type", PrepRequest: addValidSignature}, - {Label: "Webhook validation", URL: receiveURL, Data: webhookCheck, ExpectedRespStatus: 200, ExpectedRespBody: "webhook valid", PrepRequest: addValidSignature}, - {Label: "Failed Status Report", URL: receiveURL, Data: failedStatusReport, ExpectedRespStatus: 200, ExpectedRespBody: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, PrepRequest: addValidSignature}, - {Label: "Delivered Status Report", URL: receiveURL, Data: deliveredStatusReport, ExpectedRespStatus: 200, ExpectedRespBody: `Ignored`, PrepRequest: addValidSignature}, - {Label: "Subcribe", URL: receiveURL, Data: validSubscribed, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedEvent: "new_conversation", ExpectedURN: "viber:01234567890A=", PrepRequest: addValidSignature}, - {Label: "Subcribe Invalid URN", URL: receiveURL, Data: invalidURNSubscribed, ExpectedRespStatus: 400, ExpectedRespBody: "invalid viber id", PrepRequest: addValidSignature}, - {Label: "Unsubcribe", URL: receiveURL, Data: validUnsubscribed, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedEvent: courier.StopContact, ExpectedURN: "viber:01234567890A=", PrepRequest: addValidSignature}, - {Label: "Unsubcribe Invalid URN", URL: receiveURL, Data: invalidURNUnsubscribed, ExpectedRespStatus: 400, ExpectedRespBody: "invalid viber id", PrepRequest: addValidSignature}, - {Label: "Conversation Started", URL: receiveURL, Data: validConversationStarted, ExpectedRespStatus: 200, ExpectedRespBody: "ignored conversation start", PrepRequest: addValidSignature}, + {Label: "Webhook validation", URL: receiveURL, Data: webhookCheck, ExpectedRespStatus: 200, ExpectedBodyContains: "webhook valid", PrepRequest: addValidSignature}, + {Label: "Failed Status Report", URL: receiveURL, Data: failedStatusReport, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, PrepRequest: addValidSignature}, + {Label: "Delivered Status Report", URL: receiveURL, Data: deliveredStatusReport, ExpectedRespStatus: 200, ExpectedBodyContains: `Ignored`, PrepRequest: addValidSignature}, + {Label: "Subcribe", URL: receiveURL, Data: validSubscribed, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedEvent: "new_conversation", ExpectedURN: "viber:01234567890A=", PrepRequest: addValidSignature}, + {Label: "Subcribe Invalid URN", URL: receiveURL, Data: invalidURNSubscribed, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid viber id", PrepRequest: addValidSignature}, + {Label: "Unsubcribe", URL: receiveURL, Data: validUnsubscribed, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedEvent: courier.StopContact, ExpectedURN: "viber:01234567890A=", PrepRequest: addValidSignature}, + {Label: "Unsubcribe Invalid URN", URL: receiveURL, Data: invalidURNUnsubscribed, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid viber id", PrepRequest: addValidSignature}, + {Label: "Conversation Started", URL: receiveURL, Data: validConversationStarted, ExpectedRespStatus: 200, ExpectedBodyContains: "ignored conversation start", PrepRequest: addValidSignature}, {Label: "Unexpected event", URL: receiveURL, Data: unexpectedEvent, ExpectedRespStatus: 400, - ExpectedRespBody: "not handled, unknown event: unexpected", PrepRequest: addValidSignature}, - {Label: "Message missing text", URL: receiveURL, Data: rejectedMessage, ExpectedRespStatus: 400, ExpectedRespBody: "missing text or media in message in request body", PrepRequest: addValidSignature}, - {Label: "Picture missing media", URL: receiveURL, Data: rejectedPicture, ExpectedRespStatus: 400, ExpectedRespBody: "missing text or media in message in request body", PrepRequest: addValidSignature}, - {Label: "Video missing media", URL: receiveURL, Data: rejectedVideo, ExpectedRespStatus: 400, ExpectedRespBody: "missing text or media in message in request body", PrepRequest: addValidSignature}, + ExpectedBodyContains: "not handled, unknown event: unexpected", PrepRequest: addValidSignature}, + {Label: "Message missing text", URL: receiveURL, Data: rejectedMessage, ExpectedRespStatus: 400, ExpectedBodyContains: "missing text or media in message in request body", PrepRequest: addValidSignature}, + {Label: "Picture missing media", URL: receiveURL, Data: rejectedPicture, ExpectedRespStatus: 400, ExpectedBodyContains: "missing text or media in message in request body", PrepRequest: addValidSignature}, + {Label: "Video missing media", URL: receiveURL, Data: rejectedVideo, ExpectedRespStatus: 400, ExpectedBodyContains: "missing text or media in message in request body", PrepRequest: addValidSignature}, - {Label: "Valid Contact receive", URL: receiveURL, Data: validReceiveContact, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Valid Contact receive", URL: receiveURL, Data: validReceiveContact, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("Alex: +12067799191"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", PrepRequest: addValidSignature}, - {Label: "Valid URL receive", URL: receiveURL, Data: validReceiveURL, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Valid URL receive", URL: receiveURL, Data: validReceiveURL, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("http://foo.com/"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", PrepRequest: addValidSignature}, - {Label: "Valid Location receive", URL: receiveURL, Data: validReceiveLocation, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Valid Location receive", URL: receiveURL, Data: validReceiveLocation, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("incoming msg"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", ExpectedAttachments: []string{"geo:1.200000,-1.300000"}, PrepRequest: addValidSignature}, - {Label: "Valid Sticker", URL: receiveURL, Data: validSticker, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Valid Sticker", URL: receiveURL, Data: validSticker, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("incoming msg"), ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", ExpectedExternalID: "4987381189870374000", ExpectedAttachments: []string{"https://viber.github.io/docs/img/stickers/40133.png"}, PrepRequest: addValidSignature}, } var testWelcomeMessageCases = []ChannelHandleTestCase{ { - Label: "Receive Valid", - URL: receiveURL, - Data: validMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "Accepted", - ExpectedMsgText: Sp("incoming msg"), - ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", - ExpectedExternalID: "4987381189870374000", - PrepRequest: addValidSignature}, + Label: "Receive Valid", + URL: receiveURL, + Data: validMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("incoming msg"), + ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + ExpectedExternalID: "4987381189870374000", + PrepRequest: addValidSignature}, { - Label: "Conversation Started", - URL: receiveURL, - Data: validConversationStarted, - ExpectedRespStatus: 200, - ExpectedRespBody: `{"auth_token":"Token","text":"Welcome to VP, Please subscribe here for more.","type":"text","tracking_data":"0"}`, - ExpectedEvent: "welcome_message", - ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", - PrepRequest: addValidSignature, + Label: "Conversation Started", + URL: receiveURL, + Data: validConversationStarted, + ExpectedRespStatus: 200, + ExpectedBodyContains: `{"auth_token":"Token","text":"Welcome to VP, Please subscribe here for more.","type":"text","tracking_data":"0"}`, + ExpectedEvent: "welcome_message", + ExpectedURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + PrepRequest: addValidSignature, }, } diff --git a/handlers/vk/vk_test.go b/handlers/vk/vk_test.go index 85911f40e..168a7944f 100644 --- a/handlers/vk/vk_test.go +++ b/handlers/vk/vk_test.go @@ -231,123 +231,123 @@ const keyboardJson = `{"one_time":true,"buttons":[[{"action":{"type":"text","lab var testCases = []ChannelHandleTestCase{ { - Label: "Receive Message", - URL: receiveURL, - Data: msgHelloWorld, - ExpectedRespStatus: 200, - ExpectedRespBody: "ok", - ExpectedMsgText: Sp("Hello World"), - ExpectedURN: "vk:123456", - ExpectedExternalID: "1", - ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), + Label: "Receive Message", + URL: receiveURL, + Data: msgHelloWorld, + ExpectedRespStatus: 200, + ExpectedBodyContains: "ok", + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), }, { - Label: "Receive Empty Message", - URL: receiveURL, - Data: msgEmpty, - ExpectedRespStatus: 400, - ExpectedRespBody: "no text or attachment", - ExpectedURN: "vk:123456", - ExpectedExternalID: "1", - ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), + Label: "Receive Empty Message", + URL: receiveURL, + Data: msgEmpty, + ExpectedRespStatus: 400, + ExpectedBodyContains: "no text or attachment", + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), }, { - Label: "Receive First Photo Attachment", - URL: receiveURL, - Data: msgFirstPhotoAttachment, - ExpectedRespStatus: 200, - ExpectedRespBody: "ok", - ExpectedURN: "vk:123456", - ExpectedExternalID: "1", - ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), - ExpectedAttachments: []string{"https://foo.bar/x-photo.jpg"}, + Label: "Receive First Photo Attachment", + URL: receiveURL, + Data: msgFirstPhotoAttachment, + ExpectedRespStatus: 200, + ExpectedBodyContains: "ok", + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), + ExpectedAttachments: []string{"https://foo.bar/x-photo.jpg"}, }, { - Label: "Receive First Graffiti Attachment", - URL: receiveURL, - Data: msgFirstGraffitiAttachment, - ExpectedRespStatus: 200, - ExpectedRespBody: "ok", - ExpectedURN: "vk:123456", - ExpectedExternalID: "1", - ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), - ExpectedAttachments: []string{"https://foo.bar/graffiti.png"}, + Label: "Receive First Graffiti Attachment", + URL: receiveURL, + Data: msgFirstGraffitiAttachment, + ExpectedRespStatus: 200, + ExpectedBodyContains: "ok", + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), + ExpectedAttachments: []string{"https://foo.bar/graffiti.png"}, }, { - Label: "Receive First Sticker Attachment", - URL: receiveURL, - Data: msgFirstStickerAttachment, - ExpectedRespStatus: 200, - ExpectedRespBody: "ok", - ExpectedURN: "vk:123456", - ExpectedExternalID: "1", - ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), - ExpectedAttachments: []string{"https://foo.bar/128x128_sticker.png"}, + Label: "Receive First Sticker Attachment", + URL: receiveURL, + Data: msgFirstStickerAttachment, + ExpectedRespStatus: 200, + ExpectedBodyContains: "ok", + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), + ExpectedAttachments: []string{"https://foo.bar/128x128_sticker.png"}, }, { - Label: "Receive First Audio Attachment", - URL: receiveURL, - Data: msgFirstAudioAttachment, - ExpectedRespStatus: 200, - ExpectedRespBody: "ok", - ExpectedURN: "vk:123456", - ExpectedExternalID: "1", - ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), - ExpectedAttachments: []string{"https://foo.bar/audio.mp3"}, + Label: "Receive First Audio Attachment", + URL: receiveURL, + Data: msgFirstAudioAttachment, + ExpectedRespStatus: 200, + ExpectedBodyContains: "ok", + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), + ExpectedAttachments: []string{"https://foo.bar/audio.mp3"}, }, { - Label: "Receive First Audio Attachment", - URL: receiveURL, - Data: msgFirstDocAttachment, - ExpectedRespStatus: 200, - ExpectedRespBody: "ok", - ExpectedURN: "vk:123456", - ExpectedExternalID: "1", - ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), - ExpectedAttachments: []string{"https://foo.bar/doc.pdf"}, + Label: "Receive First Audio Attachment", + URL: receiveURL, + Data: msgFirstDocAttachment, + ExpectedRespStatus: 200, + ExpectedBodyContains: "ok", + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), + ExpectedAttachments: []string{"https://foo.bar/doc.pdf"}, }, { - Label: "Receive Message Keyboard", - URL: receiveURL, - Data: msgKeyboard, - ExpectedRespStatus: 200, - ExpectedRespBody: "ok", - ExpectedMsgText: Sp("Yes"), - ExpectedURN: "vk:123456", - ExpectedExternalID: "1", - ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), + Label: "Receive Message Keyboard", + URL: receiveURL, + Data: msgKeyboard, + ExpectedRespStatus: 200, + ExpectedBodyContains: "ok", + ExpectedMsgText: Sp("Yes"), + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), }, { - Label: "Receive Geolocation Attachment", - URL: receiveURL, - Data: msgGeolocationOnly, - ExpectedRespStatus: 200, - ExpectedRespBody: "ok", - ExpectedURN: "vk:123456", - ExpectedExternalID: "1", - ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), - ExpectedAttachments: []string{"geo:-9.652278,-35.701095"}, + Label: "Receive Geolocation Attachment", + URL: receiveURL, + Data: msgGeolocationOnly, + ExpectedRespStatus: 200, + ExpectedBodyContains: "ok", + ExpectedURN: "vk:123456", + ExpectedExternalID: "1", + ExpectedDate: time.Date(2020, 1, 27, 11, 50, 0, 0, time.UTC), + ExpectedAttachments: []string{"geo:-9.652278,-35.701095"}, }, { - Label: "Validate secret", - URL: receiveURL, - Data: eventWithSecret, - ExpectedRespStatus: 200, - ExpectedRespBody: "no message or server verification event", + Label: "Validate secret", + URL: receiveURL, + Data: eventWithSecret, + ExpectedRespStatus: 200, + ExpectedBodyContains: "no message or server verification event", }, { - Label: "Invalidate secret", - URL: receiveURL, - Data: eventWithoutSecret, - ExpectedRespStatus: 400, - ExpectedRespBody: "wrong secret key", + Label: "Invalidate secret", + URL: receiveURL, + Data: eventWithoutSecret, + ExpectedRespStatus: 400, + ExpectedBodyContains: "wrong secret key", }, { - Label: "Verify server", - URL: receiveURL, - Data: eventServerVerification, - ExpectedRespStatus: 200, - ExpectedRespBody: "a1b2c3", + Label: "Verify server", + URL: receiveURL, + Data: eventServerVerification, + ExpectedRespStatus: 200, + ExpectedBodyContains: "a1b2c3", }, } diff --git a/handlers/wavy/wavy_test.go b/handlers/wavy/wavy_test.go index 1e1768f4f..70bb30263 100644 --- a/handlers/wavy/wavy_test.go +++ b/handlers/wavy/wavy_test.go @@ -76,87 +76,87 @@ var ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Message", - URL: receiveURL, - Data: validReceive, - ExpectedRespStatus: 200, - ExpectedRespBody: "Message Accepted", - ExpectedMsgText: Sp("Eu quero pizza"), - ExpectedURN: "tel:+5516981562820", - ExpectedExternalID: "external_id", - ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + Label: "Receive Message", + URL: receiveURL, + Data: validReceive, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Message Accepted", + ExpectedMsgText: Sp("Eu quero pizza"), + ExpectedURN: "tel:+5516981562820", + ExpectedExternalID: "external_id", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), }, { - Label: "Invalid JSON receive", - URL: receiveURL, - Data: `blargh`, - ExpectedRespStatus: 400, - ExpectedRespBody: "unable to parse request JSON", + Label: "Invalid JSON receive", + URL: receiveURL, + Data: `blargh`, + ExpectedRespStatus: 400, + ExpectedBodyContains: "unable to parse request JSON", }, { - Label: "Missing Keys receive", - URL: receiveURL, - Data: `{}`, - ExpectedRespStatus: 400, - ExpectedRespBody: "validation for 'ID' failed on the 'required'", + Label: "Missing Keys receive", + URL: receiveURL, + Data: `{}`, + ExpectedRespStatus: 400, + ExpectedBodyContains: "validation for 'ID' failed on the 'required'", }, { - Label: "Sent Status Valid", - URL: sentStatusURL, - Data: validSentStatus, - ExpectedRespStatus: 200, - ExpectedRespBody: "Status Update Accepted", - ExpectedMsgStatus: courier.MsgSent, + Label: "Sent Status Valid", + URL: sentStatusURL, + Data: validSentStatus, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Status Update Accepted", + ExpectedMsgStatus: courier.MsgSent, }, { - Label: "Unknown Sent Status Valid", - URL: sentStatusURL, - Data: unknownSentStatus, - ExpectedRespStatus: 400, - ExpectedRespBody: "unknown sent status code", + Label: "Unknown Sent Status Valid", + URL: sentStatusURL, + Data: unknownSentStatus, + ExpectedRespStatus: 400, + ExpectedBodyContains: "unknown sent status code", }, { - Label: "Invalid JSON sent Status", - URL: sentStatusURL, - Data: `blargh`, - ExpectedRespStatus: 400, - ExpectedRespBody: "unable to parse request JSON", + Label: "Invalid JSON sent Status", + URL: sentStatusURL, + Data: `blargh`, + ExpectedRespStatus: 400, + ExpectedBodyContains: "unable to parse request JSON", }, { - Label: "Missing Keys sent Status", - URL: sentStatusURL, - Data: `{}`, - ExpectedRespStatus: 400, - ExpectedRespBody: "validation for 'CollerationID' failed on the 'required'", + Label: "Missing Keys sent Status", + URL: sentStatusURL, + Data: `{}`, + ExpectedRespStatus: 400, + ExpectedBodyContains: "validation for 'CollerationID' failed on the 'required'", }, { - Label: "Delivered Status Valid", - URL: deliveredStatusURL, - Data: validDeliveredStatus, - ExpectedRespStatus: 200, - ExpectedRespBody: "Status Update Accepted", - ExpectedMsgStatus: courier.MsgDelivered, + Label: "Delivered Status Valid", + URL: deliveredStatusURL, + Data: validDeliveredStatus, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Status Update Accepted", + ExpectedMsgStatus: courier.MsgDelivered, }, { - Label: "Unknown Delivered Status Valid", - URL: deliveredStatusURL, - Data: unknownDeliveredStatus, - ExpectedRespStatus: 400, - ExpectedRespBody: "unknown delivered status code", + Label: "Unknown Delivered Status Valid", + URL: deliveredStatusURL, + Data: unknownDeliveredStatus, + ExpectedRespStatus: 400, + ExpectedBodyContains: "unknown delivered status code", }, { - Label: "Invalid JSON delivered Statu", - URL: deliveredStatusURL, - Data: `blargh`, - ExpectedRespStatus: 400, - ExpectedRespBody: "unable to parse request JSON", + Label: "Invalid JSON delivered Statu", + URL: deliveredStatusURL, + Data: `blargh`, + ExpectedRespStatus: 400, + ExpectedBodyContains: "unable to parse request JSON", }, { - Label: "Missing Keys sent Status", - URL: deliveredStatusURL, - Data: `{}`, - ExpectedRespStatus: 400, - ExpectedRespBody: "validation for 'CollerationID' failed on the 'required'", + Label: "Missing Keys sent Status", + URL: deliveredStatusURL, + Data: `{}`, + ExpectedRespStatus: 400, + ExpectedBodyContains: "validation for 'CollerationID' failed on the 'required'", }, } diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index ac34f2ed4..19fd459c8 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -140,27 +140,27 @@ func addInvalidSignature(r *http.Request) { } var testCases = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Simple Message"), ExpectedURN: "wechat:1234", ExpectedExternalID: "123456", ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, - {Label: "Missing params", URL: receiveURL, Data: missingParamsRequired, ExpectedRespStatus: 400, ExpectedRespBody: "Error:Field validation"}, - {Label: "Missing params Event or MsgId", URL: receiveURL, Data: missingParams, ExpectedRespStatus: 400, ExpectedRespBody: "missing parameters, must have either 'MsgId' or 'Event'"}, + {Label: "Missing params", URL: receiveURL, Data: missingParamsRequired, ExpectedRespStatus: 400, ExpectedBodyContains: "Error:Field validation"}, + {Label: "Missing params Event or MsgId", URL: receiveURL, Data: missingParams, ExpectedRespStatus: 400, ExpectedBodyContains: "missing parameters, must have either 'MsgId' or 'Event'"}, - {Label: "Receive Image", URL: receiveURL, Data: imageMessage, ExpectedRespStatus: 200, ExpectedRespBody: "", + {Label: "Receive Image", URL: receiveURL, Data: imageMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp(""), ExpectedURN: "wechat:1234", ExpectedExternalID: "123456", ExpectedAttachments: []string{"https://api.weixin.qq.com/cgi-bin/media/get?media_id=12"}, ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, - {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedRespStatus: 200, ExpectedRespBody: "Event Accepted", + {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "Event Accepted", ExpectedEvent: courier.NewConversation, ExpectedURN: "wechat:1234"}, - {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, ExpectedRespStatus: 200, ExpectedRespBody: "unknown event"}, + {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "unknown event"}, - {Label: "Verify URL", URL: receiveURL, ExpectedRespStatus: 200, ExpectedRespBody: "SUCCESS", + {Label: "Verify URL", URL: receiveURL, ExpectedRespStatus: 200, ExpectedBodyContains: "SUCCESS", PrepRequest: addValidSignature}, - {Label: "Verify URL Invalid signature", URL: receiveURL, ExpectedRespStatus: 400, ExpectedRespBody: "unknown request", + {Label: "Verify URL Invalid signature", URL: receiveURL, ExpectedRespStatus: 400, ExpectedBodyContains: "unknown request", PrepRequest: addInvalidSignature}, } @@ -189,27 +189,27 @@ func TestFetchAccessToken(t *testing.T) { RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ { - Label: "Receive Message", - URL: receiveURL, - Data: validMsg, - ExpectedRespStatus: 200, - ExpectedRespBody: "", - ExpectedMsgText: Sp("Simple Message"), - ExpectedURN: "wechat:1234", + Label: "Receive Message", + URL: receiveURL, + Data: validMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "", + ExpectedMsgText: Sp("Simple Message"), + ExpectedURN: "wechat:1234", }, { - Label: "Verify URL", - URL: receiveURL, - ExpectedRespStatus: 200, - ExpectedRespBody: "SUCCESS", - PrepRequest: addValidSignature, + Label: "Verify URL", + URL: receiveURL, + ExpectedRespStatus: 200, + ExpectedBodyContains: "SUCCESS", + PrepRequest: addValidSignature, }, { - Label: "Verify URL Invalid signature", - URL: receiveURL, - ExpectedRespStatus: 400, - ExpectedRespBody: "unknown request", - PrepRequest: addInvalidSignature, + Label: "Verify URL Invalid signature", + URL: receiveURL, + ExpectedRespStatus: 400, + ExpectedBodyContains: "unknown request", + PrepRequest: addInvalidSignature, }, }) diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index 196aba6ca..df90cc449 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -292,37 +292,37 @@ var ( ) var waTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: waReceiveURL, Data: helloMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, + {Label: "Receive Valid Message", URL: waReceiveURL, Data: helloMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, ExpectedContactName: Sp("Jerry Cooney"), ExpectedMsgText: Sp("hello world"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Duplicate Valid Message", URL: waReceiveURL, Data: duplicateMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, + {Label: "Receive Duplicate Valid Message", URL: waReceiveURL, Data: duplicateMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, ExpectedMsgText: Sp("hello world"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Audio Message", URL: waReceiveURL, Data: audioMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, + {Label: "Receive Valid Audio Message", URL: waReceiveURL, Data: audioMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Button Message", URL: waReceiveURL, Data: buttonMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, + {Label: "Receive Valid Button Message", URL: waReceiveURL, Data: buttonMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, ExpectedMsgText: Sp("BUTTON1"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Document Message", URL: waReceiveURL, Data: documentMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, + {Label: "Receive Valid Document Message", URL: waReceiveURL, Data: documentMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, ExpectedMsgText: Sp("the caption"), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Image Message", URL: waReceiveURL, Data: imageMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, + {Label: "Receive Valid Image Message", URL: waReceiveURL, Data: imageMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, ExpectedMsgText: Sp("the caption"), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Interactive Button Message", URL: waReceiveURL, Data: interactiveButtonMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, + {Label: "Receive Valid Interactive Button Message", URL: waReceiveURL, Data: interactiveButtonMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, ExpectedMsgText: Sp("BUTTON1"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Interactive List Message", URL: waReceiveURL, Data: interactiveListMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, + {Label: "Receive Valid Interactive List Message", URL: waReceiveURL, Data: interactiveListMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, ExpectedMsgText: Sp("ROW1"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Location Message", URL: waReceiveURL, Data: locationMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, + {Label: "Receive Valid Location Message", URL: waReceiveURL, Data: locationMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Video Message", URL: waReceiveURL, Data: videoMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, + {Label: "Receive Valid Video Message", URL: waReceiveURL, Data: videoMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Voice Message", URL: waReceiveURL, Data: voiceMsg, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"msg"`, + {Label: "Receive Valid Voice Message", URL: waReceiveURL, Data: voiceMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: invalidMsg, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse"}, - {Label: "Receive Invalid From", URL: waReceiveURL, Data: invalidFrom, ExpectedRespStatus: 400, ExpectedRespBody: "invalid whatsapp id"}, - {Label: "Receive Invalid Timestamp", URL: waReceiveURL, Data: invalidTimestamp, ExpectedRespStatus: 400, ExpectedRespBody: "invalid timestamp"}, + {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: invalidMsg, ExpectedRespStatus: 400, ExpectedBodyContains: "unable to parse"}, + {Label: "Receive Invalid From", URL: waReceiveURL, Data: invalidFrom, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid whatsapp id"}, + {Label: "Receive Invalid Timestamp", URL: waReceiveURL, Data: invalidTimestamp, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid timestamp"}, - {Label: "Receive Valid Status", URL: waReceiveURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"type":"status"`, + {Label: "Receive Valid Status", URL: waReceiveURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"status"`, ExpectedMsgStatus: "S", ExpectedExternalID: "9712A34B4A8B6AD50F"}, - {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: "not json", ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse"}, - {Label: "Receive Invalid Status", URL: waReceiveURL, Data: invalidStatus, ExpectedRespStatus: 400, ExpectedRespBody: `"unknown status: in_orbit"`}, - {Label: "Receive Ignore Status", URL: waReceiveURL, Data: ignoreStatus, ExpectedRespStatus: 200, ExpectedRespBody: `"ignoring status: deleted"`}, + {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: "not json", ExpectedRespStatus: 400, ExpectedBodyContains: "unable to parse"}, + {Label: "Receive Invalid Status", URL: waReceiveURL, Data: invalidStatus, ExpectedRespStatus: 400, ExpectedBodyContains: `"unknown status: in_orbit"`}, + {Label: "Receive Ignore Status", URL: waReceiveURL, Data: ignoreStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `"ignoring status: deleted"`}, } func TestBuildMediaRequest(t *testing.T) { diff --git a/handlers/yo/yo_test.go b/handlers/yo/yo_test.go index fb6d14c0a..87b4286d8 100644 --- a/handlers/yo/yo_test.go +++ b/handlers/yo/yo_test.go @@ -26,18 +26,18 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, - {Label: "Receive Valid From", URL: receiveValidMessageFrom, Data: "", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid From", URL: receiveValidMessageFrom, Data: "", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729"}, - {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Message With Date", URL: receiveValidMessageWithDate, Data: "", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, int(500*time.Millisecond), time.UTC)}, - {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "", ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", + {Label: "Receive Valid Message With Time", URL: receiveValidMessageWithTime, Data: "", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedDate: time.Date(2017, 6, 23, 12, 30, 0, 0, time.UTC)}, - {Label: "Invalid URN", URL: receiveInvalidURN, Data: "", ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "", ExpectedRespStatus: 400, ExpectedRespBody: "must have one of 'sender' or 'from'"}, - {Label: "Receive No Sender", URL: receiveNoSender, Data: "", ExpectedRespStatus: 400, ExpectedRespBody: "must have one of 'sender' or 'from'"}, - {Label: "Receive Invalid Date", URL: receiveInvalidDate, Data: "", ExpectedRespStatus: 400, ExpectedRespBody: "invalid date format, must be RFC 3339"}, + {Label: "Invalid URN", URL: receiveInvalidURN, Data: "", ExpectedRespStatus: 400, ExpectedBodyContains: "phone number supplied is not a number"}, + {Label: "Receive No Params", URL: receiveNoParams, Data: "", ExpectedRespStatus: 400, ExpectedBodyContains: "must have one of 'sender' or 'from'"}, + {Label: "Receive No Sender", URL: receiveNoSender, Data: "", ExpectedRespStatus: 400, ExpectedBodyContains: "must have one of 'sender' or 'from'"}, + {Label: "Receive Invalid Date", URL: receiveInvalidDate, Data: "", ExpectedRespStatus: 400, ExpectedBodyContains: "invalid date format, must be RFC 3339"}, } func TestHandler(t *testing.T) { diff --git a/handlers/zenvia/zenvia_test.go b/handlers/zenvia/zenvia_test.go index d4d467f20..85456c120 100644 --- a/handlers/zenvia/zenvia_test.go +++ b/handlers/zenvia/zenvia_test.go @@ -163,45 +163,45 @@ var missingFieldsReceive = `{ }` var testWhatappCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveWhatsappURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", + {Label: "Receive Valid", URL: receiveWhatsappURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedBodyContains: "Message Accepted", ExpectedMsgText: Sp("Msg"), ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, - {Label: "Receive file Valid", URL: receiveWhatsappURL, Data: fileReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", + {Label: "Receive file Valid", URL: receiveWhatsappURL, Data: fileReceive, ExpectedRespStatus: 200, ExpectedBodyContains: "Message Accepted", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, - {Label: "Receive location Valid", URL: receiveWhatsappURL, Data: locationReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", + {Label: "Receive location Valid", URL: receiveWhatsappURL, Data: locationReceive, ExpectedRespStatus: 200, ExpectedBodyContains: "Message Accepted", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, - {Label: "Not JSON body", URL: receiveWhatsappURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: receiveWhatsappURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedRespBody: "request JSON doesn't match required schema"}, - {Label: "Missing field", URL: receiveWhatsappURL, Data: missingFieldsReceive, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'ID' failed on the 'required'"}, - {Label: "Bad Date", URL: receiveWhatsappURL, Data: invalidDateReceive, ExpectedRespStatus: 400, ExpectedRespBody: "invalid date format"}, + {Label: "Not JSON body", URL: receiveWhatsappURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedBodyContains: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: receiveWhatsappURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedBodyContains: "request JSON doesn't match required schema"}, + {Label: "Missing field", URL: receiveWhatsappURL, Data: missingFieldsReceive, ExpectedRespStatus: 400, ExpectedBodyContains: "validation for 'ID' failed on the 'required'"}, + {Label: "Bad Date", URL: receiveWhatsappURL, Data: invalidDateReceive, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid date format"}, - {Label: "Valid Status", URL: statusWhatsppURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `Accepted`, ExpectedMsgStatus: "S"}, - {Label: "Unkown Status", URL: statusWhatsppURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgStatus: "E"}, - {Label: "Not JSON body", URL: statusWhatsppURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: statusWhatsppURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedRespBody: "request JSON doesn't match required schema"}, + {Label: "Valid Status", URL: statusWhatsppURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `Accepted`, ExpectedMsgStatus: "S"}, + {Label: "Unkown Status", URL: statusWhatsppURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgStatus: "E"}, + {Label: "Not JSON body", URL: statusWhatsppURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedBodyContains: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: statusWhatsppURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedBodyContains: "request JSON doesn't match required schema"}, } var testSMSCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveSMSURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", + {Label: "Receive Valid", URL: receiveSMSURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedBodyContains: "Message Accepted", ExpectedMsgText: Sp("Msg"), ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, - {Label: "Receive file Valid", URL: receiveSMSURL, Data: fileReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", + {Label: "Receive file Valid", URL: receiveSMSURL, Data: fileReceive, ExpectedRespStatus: 200, ExpectedBodyContains: "Message Accepted", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, - {Label: "Receive location Valid", URL: receiveSMSURL, Data: locationReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", + {Label: "Receive location Valid", URL: receiveSMSURL, Data: locationReceive, ExpectedRespStatus: 200, ExpectedBodyContains: "Message Accepted", ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: "whatsapp:254791541111", ExpectedDate: time.Date(2017, 5, 3, 03, 04, 45, 0, time.UTC)}, - {Label: "Not JSON body", URL: receiveSMSURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: receiveSMSURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedRespBody: "request JSON doesn't match required schema"}, - {Label: "Missing field", URL: receiveSMSURL, Data: missingFieldsReceive, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'ID' failed on the 'required'"}, - {Label: "Bad Date", URL: receiveSMSURL, Data: invalidDateReceive, ExpectedRespStatus: 400, ExpectedRespBody: "invalid date format"}, + {Label: "Not JSON body", URL: receiveSMSURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedBodyContains: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: receiveSMSURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedBodyContains: "request JSON doesn't match required schema"}, + {Label: "Missing field", URL: receiveSMSURL, Data: missingFieldsReceive, ExpectedRespStatus: 400, ExpectedBodyContains: "validation for 'ID' failed on the 'required'"}, + {Label: "Bad Date", URL: receiveSMSURL, Data: invalidDateReceive, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid date format"}, - {Label: "Valid Status", URL: statusSMSURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `Accepted`, ExpectedMsgStatus: "S"}, - {Label: "Unkown Status", URL: statusSMSURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgStatus: "E"}, - {Label: "Not JSON body", URL: statusSMSURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: statusSMSURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedRespBody: "request JSON doesn't match required schema"}, + {Label: "Valid Status", URL: statusSMSURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `Accepted`, ExpectedMsgStatus: "S"}, + {Label: "Unkown Status", URL: statusSMSURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgStatus: "E"}, + {Label: "Not JSON body", URL: statusSMSURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedBodyContains: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: statusSMSURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedBodyContains: "request JSON doesn't match required schema"}, } func TestHandler(t *testing.T) { diff --git a/handlers/zenviaold/zenviaold_test.go b/handlers/zenviaold/zenviaold_test.go index b80cca6d9..655b2c069 100644 --- a/handlers/zenviaold/zenviaold_test.go +++ b/handlers/zenviaold/zenviaold_test.go @@ -106,21 +106,21 @@ var missingFieldsReceive = `{ }` var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedRespBody: "Message Accepted", + {Label: "Receive Valid", URL: receiveURL, Data: validReceive, ExpectedRespStatus: 200, ExpectedBodyContains: "Message Accepted", ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+254791541111", ExpectedDate: time.Date(2017, 5, 3, 06, 04, 45, 123000000, time.UTC)}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedRespBody: "phone number supplied is not a number"}, - {Label: "Not JSON body", URL: receiveURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: receiveURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedRespBody: "request JSON doesn't match required schema"}, - {Label: "Missing field", URL: receiveURL, Data: missingFieldsReceive, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'ID' failed on the 'required'"}, - {Label: "Bad Date", URL: receiveURL, Data: invalidDateReceive, ExpectedRespStatus: 400, ExpectedRespBody: "invalid date format"}, - - {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedRespBody: `Accepted`, ExpectedMsgStatus: "D"}, - {Label: "Valid Status with more fields", URL: statusURL, Data: validWithMoreFieldsStatus, ExpectedRespStatus: 200, ExpectedRespBody: `Accepted`, ExpectedMsgStatus: "D"}, - {Label: "Unkown Status", URL: statusURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedRespBody: "Accepted", ExpectedMsgStatus: "E"}, - {Label: "Not JSON body", URL: statusURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedRespBody: "unable to parse request JSON"}, - {Label: "Wrong JSON schema", URL: statusURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedRespBody: "request JSON doesn't match required schema"}, - {Label: "Missing field", URL: statusURL, Data: missingFieldsStatus, ExpectedRespStatus: 400, ExpectedRespBody: "validation for 'StatusCode' failed on the 'required'"}, + {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedBodyContains: "phone number supplied is not a number"}, + {Label: "Not JSON body", URL: receiveURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedBodyContains: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: receiveURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedBodyContains: "request JSON doesn't match required schema"}, + {Label: "Missing field", URL: receiveURL, Data: missingFieldsReceive, ExpectedRespStatus: 400, ExpectedBodyContains: "validation for 'ID' failed on the 'required'"}, + {Label: "Bad Date", URL: receiveURL, Data: invalidDateReceive, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid date format"}, + + {Label: "Valid Status", URL: statusURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `Accepted`, ExpectedMsgStatus: "D"}, + {Label: "Valid Status with more fields", URL: statusURL, Data: validWithMoreFieldsStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `Accepted`, ExpectedMsgStatus: "D"}, + {Label: "Unkown Status", URL: statusURL, Data: unknownStatus, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", ExpectedMsgStatus: "E"}, + {Label: "Not JSON body", URL: statusURL, Data: notJSON, ExpectedRespStatus: 400, ExpectedBodyContains: "unable to parse request JSON"}, + {Label: "Wrong JSON schema", URL: statusURL, Data: wrongJSONSchema, ExpectedRespStatus: 400, ExpectedBodyContains: "request JSON doesn't match required schema"}, + {Label: "Missing field", URL: statusURL, Data: missingFieldsStatus, ExpectedRespStatus: 400, ExpectedBodyContains: "validation for 'StatusCode' failed on the 'required'"}, } func TestHandler(t *testing.T) { From 5b8265da8d671ca2d7302ef8ccd6d31701d5db8b Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 15 Sep 2022 10:24:06 -0500 Subject: [PATCH 169/294] Update CHANGELOG.md for v7.5.28 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70dbc1a31..f6a8a3050 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.28 +---------- + * Update to use SHA256 signature for FBA payload, increase max body bytes limit to 1MiB + * Meta channels webhooks requests, should always return 200 status + v7.5.27 ---------- * Fix server logging when channel is nil From f9dc436b2707d59a457f617e9aad10a4f0abc29d Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 15 Sep 2022 11:07:57 -0500 Subject: [PATCH 170/294] Make it easier to override error responses per handler --- handler.go | 3 ++- handler_test.go | 5 ++++- handlers/base.go | 7 +------ handlers/facebookapp/facebookapp.go | 7 +------ handlers/facebookapp/facebookapp_test.go | 16 ++++++++-------- handlers/viber/viber.go | 2 +- responses.go | 8 ++++---- server.go | 18 +++++------------- 8 files changed, 26 insertions(+), 40 deletions(-) diff --git a/handler.go b/handler.go index 12fad794a..6f6280e5f 100644 --- a/handler.go +++ b/handler.go @@ -24,10 +24,11 @@ type ChannelHandler interface { ChannelType() ChannelType ChannelName() string UseChannelRouteUUID() bool - ErrorResponseStatus() int RedactValues(Channel) []string GetChannel(context.Context, *http.Request) (Channel, error) Send(context.Context, Msg, *ChannelLog) (MsgStatus, error) + + WriteRequestError(context.Context, http.ResponseWriter, *http.Request, error) error } // URNDescriber is the interface handlers which can look up URN metadata for new contacts should satisfy. diff --git a/handler_test.go b/handler_test.go index a336ac6d7..09330a76c 100644 --- a/handler_test.go +++ b/handler_test.go @@ -33,7 +33,6 @@ func (h *dummyHandler) ChannelName() string { return "Dummy Ha func (h *dummyHandler) ChannelType() courier.ChannelType { return courier.ChannelType("DM") } func (h *dummyHandler) UseChannelRouteUUID() bool { return true } func (h *dummyHandler) RedactValues(courier.Channel) []string { return []string{"sesame"} } -func (h *dummyHandler) ErrorResponseStatus() int { return 400 } func (h *dummyHandler) GetChannel(ctx context.Context, r *http.Request) (courier.Channel, error) { dmChannel := test.NewMockChannel("e4bb1578-29da-4fa5-a214-9da19dd24230", "DM", "2020", "US", map[string]interface{}{}) @@ -61,6 +60,10 @@ func (h *dummyHandler) Send(ctx context.Context, msg courier.Msg, clog *courier. return h.backend.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgSent, clog), nil } +func (h *dummyHandler) WriteRequestError(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) error { + return courier.WriteError(ctx, w, r, http.StatusBadRequest, err) +} + // ReceiveMsg sends the passed in message, returning any error func (h *dummyHandler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { r.ParseForm() diff --git a/handlers/base.go b/handlers/base.go index 058d97726..dd7e5603c 100644 --- a/handlers/base.go +++ b/handlers/base.go @@ -66,11 +66,6 @@ func (h *BaseHandler) UseChannelRouteUUID() bool { return h.useChannelRouteUUID } -// ErrorResponseStatus() return the response status code for errors -func (h *BaseHandler) ErrorResponseStatus() int { - return 400 -} - func (h *BaseHandler) RedactValues(ch courier.Channel) []string { if ch == nil { return nil @@ -108,7 +103,7 @@ func (h *BaseHandler) WriteMsgSuccessResponse(ctx context.Context, w http.Respon // WriteRequestError writes the passed in error to our response writer func (h *BaseHandler) WriteRequestError(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) error { - return courier.WriteError(ctx, w, r, err) + return courier.WriteError(ctx, w, r, http.StatusBadRequest, err) } // WriteRequestIgnored writes an ignored payload to our response writer diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 39a55a2cc..f2f6a2bd3 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -274,12 +274,7 @@ func (h *handler) RedactValues(ch courier.Channel) []string { // WriteRequestError writes the passed in error to our response writer func (h *handler) WriteRequestError(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) error { - return courier.WriteIgnored(ctx, w, r, fmt.Sprintf("ignoring request, %s", err.Error())) -} - -// ErrorResponseStatus() return the response status code for errors -func (h *handler) ErrorResponseStatus() int { - return 200 + return courier.WriteError(ctx, w, r, http.StatusOK, err) } // GetChannel returns the channel diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 9069667d9..14d972c8e 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -50,7 +50,7 @@ var testCasesFBA = []ChannelHandleTestCase{ URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/helloMsgFBA.json")), ExpectedRespStatus: 200, - ExpectedBodyContains: "ignoring request, invalid request signature", + ExpectedBodyContains: "invalid request signature", PrepRequest: addInvalidSignature, }, { @@ -246,7 +246,7 @@ var testCasesFBA = []ChannelHandleTestCase{ URL: "/c/fba/receive", Data: string(test.ReadFile("./testdata/fba/invalidURNFBA.json")), ExpectedRespStatus: 200, - ExpectedBodyContains: "ignoring request, invalid facebook id", + ExpectedBodyContains: "invalid facebook id", PrepRequest: addValidSignature, }, } @@ -271,7 +271,7 @@ var testCasesIG = []ChannelHandleTestCase{ URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/helloMsgIG.json")), ExpectedRespStatus: 200, - ExpectedBodyContains: "ignoring request, invalid request signature", + ExpectedBodyContains: "invalid request signature", PrepRequest: addInvalidSignature, }, { @@ -384,7 +384,7 @@ var testCasesIG = []ChannelHandleTestCase{ URL: "/c/ig/receive", Data: string(test.ReadFile("./testdata/ig/invalidURNIG.json")), ExpectedRespStatus: 200, - ExpectedBodyContains: "ignoring request, invalid instagram id", + ExpectedBodyContains: "invalid instagram id", PrepRequest: addValidSignature, }, { @@ -683,7 +683,7 @@ var testCasesWAC = []ChannelHandleTestCase{ URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidFrom.json")), ExpectedRespStatus: 200, - ExpectedBodyContains: "ignoring request, invalid whatsapp id", + ExpectedBodyContains: "invalid whatsapp id", PrepRequest: addValidSignature, }, { @@ -691,7 +691,7 @@ var testCasesWAC = []ChannelHandleTestCase{ URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidTimestamp.json")), ExpectedRespStatus: 200, - ExpectedBodyContains: "ignoring request, invalid timestamp", + ExpectedBodyContains: "invalid timestamp", PrepRequest: addValidSignature, }, { @@ -699,7 +699,7 @@ var testCasesWAC = []ChannelHandleTestCase{ URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/helloWAC.json")), ExpectedRespStatus: 200, - ExpectedBodyContains: "ignoring request, invalid request signature", + ExpectedBodyContains: "invalid request signature", NoQueueErrorCheck: true, NoInvalidChannelCheck: true, PrepRequest: addInvalidSignature, @@ -719,7 +719,7 @@ var testCasesWAC = []ChannelHandleTestCase{ URL: wacReceiveURL, Data: string(test.ReadFile("./testdata/wac/invalidStatusWAC.json")), ExpectedRespStatus: 200, - ExpectedBodyContains: `"ignoring request, unknown status: in_orbit"`, + ExpectedBodyContains: `"unknown status: in_orbit"`, PrepRequest: addValidSignature, }, { diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index 7155583a2..5c406192d 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -235,7 +235,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } - return nil, courier.WriteError(ctx, w, r, fmt.Errorf("not handled, unknown event: %s", event)) + return nil, courier.WriteError(ctx, w, r, http.StatusBadRequest, fmt.Errorf("not handled, unknown event: %s", event)) } func writeWelcomeMessageResponse(w http.ResponseWriter, channel courier.Channel, event courier.Event) error { diff --git a/responses.go b/responses.go index 90e10d946..10dd59fea 100644 --- a/responses.go +++ b/responses.go @@ -13,13 +13,13 @@ import ( ) // writeAndLogRequestError writes a JSON response for the passed in message and logs an info messages -func writeAndLogRequestError(ctx context.Context, w http.ResponseWriter, r *http.Request, c Channel, err error) error { +func writeAndLogRequestError(ctx context.Context, h ChannelHandler, w http.ResponseWriter, r *http.Request, c Channel, err error) error { LogRequestError(r, c, err) - return WriteError(ctx, w, r, err) + return h.WriteRequestError(ctx, w, r, err) } // WriteError writes a JSON response for the passed in error -func WriteError(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) error { +func WriteError(ctx context.Context, w http.ResponseWriter, r *http.Request, statusCode int, err error) error { errors := []interface{}{NewErrorData(err.Error())} vErrs, isValidation := err.(validator.ValidationErrors) @@ -28,7 +28,7 @@ func WriteError(ctx context.Context, w http.ResponseWriter, r *http.Request, err errors = append(errors, NewErrorData(fmt.Sprintf("field '%s' %s", strings.ToLower(vErrs[i].Field()), vErrs[i].Tag()))) } } - return WriteDataResponse(ctx, w, http.StatusBadRequest, "Error", errors) + return WriteDataResponse(ctx, w, statusCode, "Error", errors) } // WriteIgnored writes a JSON response indicating that we ignored the request diff --git a/server.go b/server.go index a58d4f822..ab612e01e 100644 --- a/server.go +++ b/server.go @@ -267,22 +267,14 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe recorder, err := httpx.NewRecorder(r, w, true) if err != nil { - writeAndLogRequestError(ctx, w, r, nil, err) + writeAndLogRequestError(ctx, handler, w, r, nil, err) return } // get the channel for this request - can be nil, e.g. FBA verification requests channel, err := handler.GetChannel(ctx, r) if err != nil { - - // webhooks for FBA, IG and WAC should always return 200 - if handler.ErrorResponseStatus() == 200 { - logrus.WithError(err).WithField("request", string(recorder.Trace.RequestTrace)) - WriteIgnored(ctx, recorder.ResponseWriter, r, fmt.Sprintf("ignoring request, %s", err.Error())) - return - } - - writeAndLogRequestError(ctx, recorder.ResponseWriter, r, channel, err) + writeAndLogRequestError(ctx, handler, recorder.ResponseWriter, r, channel, err) return } @@ -297,7 +289,7 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe if panicLog != nil { debug.PrintStack() logrus.WithError(err).WithField("channel_uuid", channelUUID).WithField("request", string(recorder.Trace.RequestTrace)).WithField("trace", panicLog).Error("panic handling request") - writeAndLogRequestError(ctx, recorder.ResponseWriter, r, channel, errors.New("panic handling msg")) + writeAndLogRequestError(ctx, handler, recorder.ResponseWriter, r, channel, errors.New("panic handling msg")) } }() @@ -310,13 +302,13 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe // if we received an error, write it out and report it if hErr != nil { logrus.WithError(hErr).WithField("channel_uuid", channelUUID).WithField("request", string(recorder.Trace.RequestTrace)).Error("error handling request") - writeAndLogRequestError(ctx, recorder.ResponseWriter, r, channel, hErr) + writeAndLogRequestError(ctx, handler, recorder.ResponseWriter, r, channel, hErr) } // end recording of the request so that we have a response trace if err := recorder.End(); err != nil { logrus.WithError(err).WithField("channel_uuid", channelUUID).WithField("request", string(recorder.Trace.RequestTrace)).Error("error recording request") - writeAndLogRequestError(ctx, w, r, channel, err) + writeAndLogRequestError(ctx, handler, w, r, channel, err) } if channel != nil { From f6abbdcdef310dedc6a386a2f6e4994f37043bff Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 15 Sep 2022 11:21:13 -0500 Subject: [PATCH 171/294] Make it easier to override all responses per handler --- handler.go | 4 ++++ handler_test.go | 13 +++++++++++++ handlers/arabiacell/arabiacell.go | 2 +- handlers/burstsms/burstsms.go | 4 ++-- handlers/clicksend/clicksend.go | 2 +- handlers/generic.go | 8 ++++---- handlers/messangi/messangi.go | 2 +- handlers/mtarget/mtarget.go | 2 +- handlers/responses.go | 21 ++++++--------------- 9 files changed, 33 insertions(+), 25 deletions(-) diff --git a/handler.go b/handler.go index 6f6280e5f..8aeefc977 100644 --- a/handler.go +++ b/handler.go @@ -21,6 +21,7 @@ type ChannelHandleFunc func(context.Context, Channel, http.ResponseWriter, *http // ChannelHandler is the interface all handlers must satisfy type ChannelHandler interface { Initialize(Server) error + Server() Server ChannelType() ChannelType ChannelName() string UseChannelRouteUUID() bool @@ -28,7 +29,10 @@ type ChannelHandler interface { GetChannel(context.Context, *http.Request) (Channel, error) Send(context.Context, Msg, *ChannelLog) (MsgStatus, error) + WriteStatusSuccessResponse(context.Context, http.ResponseWriter, *http.Request, []MsgStatus) error + WriteMsgSuccessResponse(context.Context, http.ResponseWriter, *http.Request, []Msg) error WriteRequestError(context.Context, http.ResponseWriter, *http.Request, error) error + WriteRequestIgnored(context.Context, http.ResponseWriter, *http.Request, string) error } // URNDescriber is the interface handlers which can look up URN metadata for new contacts should satisfy. diff --git a/handler_test.go b/handler_test.go index 09330a76c..c199dfa7f 100644 --- a/handler_test.go +++ b/handler_test.go @@ -29,6 +29,7 @@ func NewHandler() courier.ChannelHandler { return &dummyHandler{} } +func (h *dummyHandler) Server() courier.Server { return h.server } func (h *dummyHandler) ChannelName() string { return "Dummy Handler" } func (h *dummyHandler) ChannelType() courier.ChannelType { return courier.ChannelType("DM") } func (h *dummyHandler) UseChannelRouteUUID() bool { return true } @@ -60,10 +61,22 @@ func (h *dummyHandler) Send(ctx context.Context, msg courier.Msg, clog *courier. return h.backend.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgSent, clog), nil } +func (h *dummyHandler) WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, statuses []courier.MsgStatus) error { + return courier.WriteStatusSuccess(ctx, w, r, statuses) +} + +func (h *dummyHandler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error { + return courier.WriteMsgSuccess(ctx, w, r, msgs) +} + func (h *dummyHandler) WriteRequestError(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) error { return courier.WriteError(ctx, w, r, http.StatusBadRequest, err) } +func (h *dummyHandler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter, r *http.Request, details string) error { + return courier.WriteIgnored(ctx, w, r, details) +} + // ReceiveMsg sends the passed in message, returning any error func (h *dummyHandler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { r.ParseForm() diff --git a/handlers/arabiacell/arabiacell.go b/handlers/arabiacell/arabiacell.go index 43d2f0bdd..57623d9be 100644 --- a/handlers/arabiacell/arabiacell.go +++ b/handlers/arabiacell/arabiacell.go @@ -37,7 +37,7 @@ func newHandler() courier.ChannelHandler { // Initialize is called by the engine once everything is loaded func (h *handler) Initialize(s courier.Server) error { h.SetServer(s) - receiveHandler := handlers.NewTelReceiveHandler(&h.BaseHandler, "M", "B") + receiveHandler := handlers.NewTelReceiveHandler(h, "M", "B") s.AddHandlerRoute(h, http.MethodPost, "receive", receiveHandler) return nil } diff --git a/handlers/burstsms/burstsms.go b/handlers/burstsms/burstsms.go index e4a243935..8b6d98476 100644 --- a/handlers/burstsms/burstsms.go +++ b/handlers/burstsms/burstsms.go @@ -39,10 +39,10 @@ func newHandler() courier.ChannelHandler { // Initialize is called by the engine once everything is loaded func (h *handler) Initialize(s courier.Server) error { h.SetServer(s) - receiveHandler := handlers.NewTelReceiveHandler(&h.BaseHandler, "mobile", "response") + receiveHandler := handlers.NewTelReceiveHandler(h, "mobile", "response") s.AddHandlerRoute(h, http.MethodGet, "receive", receiveHandler) - statusHandler := handlers.NewExternalIDStatusHandler(&h.BaseHandler, statusMap, "message_id", "status") + statusHandler := handlers.NewExternalIDStatusHandler(h, statusMap, "message_id", "status") s.AddHandlerRoute(h, http.MethodGet, "status", statusHandler) return nil } diff --git a/handlers/clicksend/clicksend.go b/handlers/clicksend/clicksend.go index 69d0a649a..4734d17ea 100644 --- a/handlers/clicksend/clicksend.go +++ b/handlers/clicksend/clicksend.go @@ -34,7 +34,7 @@ func newHandler() courier.ChannelHandler { // Initialize is called by the engine once everything is loaded func (h *handler) Initialize(s courier.Server) error { h.SetServer(s) - s.AddHandlerRoute(h, http.MethodPost, "receive", handlers.NewTelReceiveHandler(&h.BaseHandler, "from", "body")) + s.AddHandlerRoute(h, http.MethodPost, "receive", handlers.NewTelReceiveHandler(h, "from", "body")) return nil } diff --git a/handlers/generic.go b/handlers/generic.go index cd774afe7..fda61938e 100644 --- a/handlers/generic.go +++ b/handlers/generic.go @@ -10,7 +10,7 @@ import ( ) // NewTelReceiveHandler creates a new receive handler given the passed in text and from fields -func NewTelReceiveHandler(h *BaseHandler, fromField string, bodyField string) courier.ChannelHandleFunc { +func NewTelReceiveHandler(h courier.ChannelHandler, fromField string, bodyField string) courier.ChannelHandleFunc { return func(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { err := r.ParseForm() if err != nil { @@ -28,13 +28,13 @@ func NewTelReceiveHandler(h *BaseHandler, fromField string, bodyField string) co return nil, WriteAndLogRequestError(ctx, h, c, w, r, err) } // build our msg - msg := h.Backend().NewIncomingMsg(c, urn, body, clog).WithReceivedOn(time.Now().UTC()) + msg := h.Server().Backend().NewIncomingMsg(c, urn, body, clog).WithReceivedOn(time.Now().UTC()) return WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } } // NewExternalIDStatusHandler creates a new status handler given the passed in status map and fields -func NewExternalIDStatusHandler(h *BaseHandler, statuses map[string]courier.MsgStatusValue, externalIDField string, statusField string) courier.ChannelHandleFunc { +func NewExternalIDStatusHandler(h courier.ChannelHandler, statuses map[string]courier.MsgStatusValue, externalIDField string, statusField string) courier.ChannelHandleFunc { return func(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { err := r.ParseForm() if err != nil { @@ -53,7 +53,7 @@ func NewExternalIDStatusHandler(h *BaseHandler, statuses map[string]courier.MsgS } // create our status - status := h.Backend().NewMsgStatusForExternalID(c, externalID, sValue, clog) + status := h.Server().Backend().NewMsgStatusForExternalID(c, externalID, sValue, clog) return WriteMsgStatusAndResponse(ctx, h, c, status, w, r) } } diff --git a/handlers/messangi/messangi.go b/handlers/messangi/messangi.go index e74c52787..94e064a5b 100644 --- a/handlers/messangi/messangi.go +++ b/handlers/messangi/messangi.go @@ -41,7 +41,7 @@ func newHandler() courier.ChannelHandler { // Initialize is called by the engine once everything is loaded func (h *handler) Initialize(s courier.Server) error { h.SetServer(s) - receiveHandler := handlers.NewTelReceiveHandler(&h.BaseHandler, "mobile", "mo") + receiveHandler := handlers.NewTelReceiveHandler(h, "mobile", "mo") s.AddHandlerRoute(h, http.MethodPost, "receive", receiveHandler) return nil } diff --git a/handlers/mtarget/mtarget.go b/handlers/mtarget/mtarget.go index 905f4166b..78d1e626b 100644 --- a/handlers/mtarget/mtarget.go +++ b/handlers/mtarget/mtarget.go @@ -46,7 +46,7 @@ func (h *handler) Initialize(s courier.Server) error { h.SetServer(s) s.AddHandlerRoute(h, http.MethodPost, "receive", h.receiveMsg) - statusHandler := handlers.NewExternalIDStatusHandler(&h.BaseHandler, statusMapping, "MsgId", "Status") + statusHandler := handlers.NewExternalIDStatusHandler(h, statusMapping, "MsgId", "Status") s.AddHandlerRoute(h, http.MethodPost, "status", statusHandler) return nil } diff --git a/handlers/responses.go b/handlers/responses.go index 7cd84d737..b3bb1744f 100644 --- a/handlers/responses.go +++ b/handlers/responses.go @@ -7,20 +7,11 @@ import ( "github.com/nyaruka/courier" ) -// ResponseWriter interace with response methods for success responses -type ResponseWriter interface { - Backend() courier.Backend - WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, statuses []courier.MsgStatus) error - WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error - WriteRequestError(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) error - WriteRequestIgnored(ctx context.Context, w http.ResponseWriter, r *http.Request, msg string) error -} - // WriteMsgsAndResponse writes the passed in message to our backend -func WriteMsgsAndResponse(ctx context.Context, h ResponseWriter, msgs []courier.Msg, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { +func WriteMsgsAndResponse(ctx context.Context, h courier.ChannelHandler, msgs []courier.Msg, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { events := make([]courier.Event, len(msgs)) for i, m := range msgs { - err := h.Backend().WriteMsg(ctx, m, clog) + err := h.Server().Backend().WriteMsg(ctx, m, clog) if err != nil { return nil, err } @@ -31,8 +22,8 @@ func WriteMsgsAndResponse(ctx context.Context, h ResponseWriter, msgs []courier. } // WriteMsgStatusAndResponse write the passed in status to our backend -func WriteMsgStatusAndResponse(ctx context.Context, h ResponseWriter, channel courier.Channel, status courier.MsgStatus, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { - err := h.Backend().WriteMsgStatus(ctx, status) +func WriteMsgStatusAndResponse(ctx context.Context, h courier.ChannelHandler, channel courier.Channel, status courier.MsgStatus, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { + err := h.Server().Backend().WriteMsgStatus(ctx, status) if err == courier.ErrMsgNotFound { return nil, WriteAndLogRequestIgnored(ctx, h, channel, w, r, "msg not found, ignored") } @@ -45,13 +36,13 @@ func WriteMsgStatusAndResponse(ctx context.Context, h ResponseWriter, channel co } // WriteAndLogRequestError logs the passed in error and writes the response to the response writer -func WriteAndLogRequestError(ctx context.Context, h ResponseWriter, channel courier.Channel, w http.ResponseWriter, r *http.Request, err error) error { +func WriteAndLogRequestError(ctx context.Context, h courier.ChannelHandler, channel courier.Channel, w http.ResponseWriter, r *http.Request, err error) error { courier.LogRequestError(r, channel, err) return h.WriteRequestError(ctx, w, r, err) } // WriteAndLogRequestIgnored logs that the passed in request was ignored and writes the response to the response writer -func WriteAndLogRequestIgnored(ctx context.Context, h ResponseWriter, channel courier.Channel, w http.ResponseWriter, r *http.Request, details string) error { +func WriteAndLogRequestIgnored(ctx context.Context, h courier.ChannelHandler, channel courier.Channel, w http.ResponseWriter, r *http.Request, details string) error { courier.LogRequestIgnored(r, channel, details) return h.WriteRequestIgnored(ctx, w, r, details) } From 09856845a2873a0b10bc7ac6dfc287801d5bd960 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 15 Sep 2022 12:12:37 -0500 Subject: [PATCH 172/294] Simplify constructing responses and add tests --- handler.go | 8 ++-- handler_test.go | 16 +++---- handlers/base.go | 16 +++---- handlers/bongolive/bongolive.go | 6 +-- handlers/dart/dart.go | 4 +- handlers/discord/discord.go | 5 --- handlers/external/external.go | 6 +-- handlers/facebookapp/facebookapp.go | 4 +- handlers/i2sms/i2sms.go | 2 +- handlers/jasmin/jasmin.go | 6 +-- handlers/jiochat/jiochat.go | 2 +- handlers/m3tech/m3tech.go | 2 +- handlers/macrokiosk/macrokiosk.go | 2 +- handlers/mtarget/mtarget.go | 2 +- handlers/responses.go | 8 ++-- handlers/start/start.go | 2 +- handlers/telegram/telegram.go | 2 +- handlers/twiml/twiml.go | 4 +- handlers/viber/viber.go | 6 +-- handlers/wechat/wechat.go | 4 +- responses.go | 12 ++--- responses_test.go | 70 +++++++++++++++++++++++++++++ 22 files changed, 127 insertions(+), 62 deletions(-) create mode 100644 responses_test.go diff --git a/handler.go b/handler.go index 8aeefc977..8816fd05f 100644 --- a/handler.go +++ b/handler.go @@ -29,10 +29,10 @@ type ChannelHandler interface { GetChannel(context.Context, *http.Request) (Channel, error) Send(context.Context, Msg, *ChannelLog) (MsgStatus, error) - WriteStatusSuccessResponse(context.Context, http.ResponseWriter, *http.Request, []MsgStatus) error - WriteMsgSuccessResponse(context.Context, http.ResponseWriter, *http.Request, []Msg) error - WriteRequestError(context.Context, http.ResponseWriter, *http.Request, error) error - WriteRequestIgnored(context.Context, http.ResponseWriter, *http.Request, string) error + WriteStatusSuccessResponse(context.Context, http.ResponseWriter, []MsgStatus) error + WriteMsgSuccessResponse(context.Context, http.ResponseWriter, []Msg) error + WriteRequestError(context.Context, http.ResponseWriter, error) error + WriteRequestIgnored(context.Context, http.ResponseWriter, string) error } // URNDescriber is the interface handlers which can look up URN metadata for new contacts should satisfy. diff --git a/handler_test.go b/handler_test.go index c199dfa7f..95dfa48a2 100644 --- a/handler_test.go +++ b/handler_test.go @@ -61,20 +61,20 @@ func (h *dummyHandler) Send(ctx context.Context, msg courier.Msg, clog *courier. return h.backend.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgSent, clog), nil } -func (h *dummyHandler) WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, statuses []courier.MsgStatus) error { - return courier.WriteStatusSuccess(ctx, w, r, statuses) +func (h *dummyHandler) WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, statuses []courier.MsgStatus) error { + return courier.WriteStatusSuccess(ctx, w, statuses) } -func (h *dummyHandler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error { - return courier.WriteMsgSuccess(ctx, w, r, msgs) +func (h *dummyHandler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { + return courier.WriteMsgSuccess(ctx, w, msgs) } -func (h *dummyHandler) WriteRequestError(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) error { - return courier.WriteError(ctx, w, r, http.StatusBadRequest, err) +func (h *dummyHandler) WriteRequestError(ctx context.Context, w http.ResponseWriter, err error) error { + return courier.WriteError(ctx, w, http.StatusBadRequest, err) } -func (h *dummyHandler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter, r *http.Request, details string) error { - return courier.WriteIgnored(ctx, w, r, details) +func (h *dummyHandler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter, details string) error { + return courier.WriteIgnored(ctx, w, details) } // ReceiveMsg sends the passed in message, returning any error diff --git a/handlers/base.go b/handlers/base.go index dd7e5603c..b3c2e67b6 100644 --- a/handlers/base.go +++ b/handlers/base.go @@ -92,21 +92,21 @@ func (h *BaseHandler) GetChannel(ctx context.Context, r *http.Request) (courier. } // WriteStatusSuccessResponse writes a success response for the statuses -func (h *BaseHandler) WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, statuses []courier.MsgStatus) error { - return courier.WriteStatusSuccess(ctx, w, r, statuses) +func (h *BaseHandler) WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, statuses []courier.MsgStatus) error { + return courier.WriteStatusSuccess(ctx, w, statuses) } // WriteMsgSuccessResponse writes a success response for the messages -func (h *BaseHandler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error { - return courier.WriteMsgSuccess(ctx, w, r, msgs) +func (h *BaseHandler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { + return courier.WriteMsgSuccess(ctx, w, msgs) } // WriteRequestError writes the passed in error to our response writer -func (h *BaseHandler) WriteRequestError(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) error { - return courier.WriteError(ctx, w, r, http.StatusBadRequest, err) +func (h *BaseHandler) WriteRequestError(ctx context.Context, w http.ResponseWriter, err error) error { + return courier.WriteError(ctx, w, http.StatusBadRequest, err) } // WriteRequestIgnored writes an ignored payload to our response writer -func (h *BaseHandler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter, r *http.Request, details string) error { - return courier.WriteIgnored(ctx, w, r, details) +func (h *BaseHandler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter, details string) error { + return courier.WriteIgnored(ctx, w, details) } diff --git a/handlers/bongolive/bongolive.go b/handlers/bongolive/bongolive.go index 826b303a9..ee0348672 100644 --- a/handlers/bongolive/bongolive.go +++ b/handlers/bongolive/bongolive.go @@ -101,15 +101,15 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } -func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error { +func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { return writeBongoLiveResponse(w) } -func (h *handler) WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, statuses []courier.MsgStatus) error { +func (h *handler) WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, statuses []courier.MsgStatus) error { return writeBongoLiveResponse(w) } -func (h *handler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter, r *http.Request, details string) error { +func (h *handler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter, details string) error { return writeBongoLiveResponse(w) } diff --git a/handlers/dart/dart.go b/handlers/dart/dart.go index 07b07ff6d..5c4f9358b 100644 --- a/handlers/dart/dart.go +++ b/handlers/dart/dart.go @@ -125,14 +125,14 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } // DartMedia expects "000" from a message receive request -func (h *handler) WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, statuses []courier.MsgStatus) error { +func (h *handler) WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, statuses []courier.MsgStatus) error { w.WriteHeader(200) _, err := fmt.Fprint(w, "000") return err } // DartMedia expects "000" from a status request -func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error { +func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { w.WriteHeader(200) _, err := fmt.Fprint(w, "000") return err diff --git a/handlers/discord/discord.go b/handlers/discord/discord.go index 16d264898..d48149f7f 100644 --- a/handlers/discord/discord.go +++ b/handlers/discord/discord.go @@ -106,11 +106,6 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } -// WriteMsgSuccessResponse writes our response in TWIML format -func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error { - return courier.WriteMsgSuccess(ctx, w, r, msgs) -} - // buildStatusHandler deals with building a handler that takes what status is received in the URL func (h *handler) buildStatusHandler(status string) courier.ChannelHandleFunc { return func(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { diff --git a/handlers/external/external.go b/handlers/external/external.go index f2f3cc220..e03c31491 100644 --- a/handlers/external/external.go +++ b/handlers/external/external.go @@ -116,7 +116,7 @@ func (h *handler) receiveStopContact(ctx context.Context, channel courier.Channe if err != nil { return nil, err } - return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(ctx, w, r, channelEvent) + return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(ctx, w, channelEvent) } // utility function to grab the form value for either the passed in name (if non-empty) or the first set @@ -220,10 +220,10 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // WriteMsgSuccessResponse writes our response in TWIML format -func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error { +func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { moResponse := msgs[0].Channel().StringConfigForKey(configMOResponse, "") if moResponse == "" { - return courier.WriteMsgSuccess(ctx, w, r, msgs) + return courier.WriteMsgSuccess(ctx, w, msgs) } moResponseContentType := msgs[0].Channel().StringConfigForKey(configMOResponseContentType, "") if moResponseContentType != "" { diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index f2f6a2bd3..c920fd132 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -273,8 +273,8 @@ func (h *handler) RedactValues(ch courier.Channel) []string { } // WriteRequestError writes the passed in error to our response writer -func (h *handler) WriteRequestError(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) error { - return courier.WriteError(ctx, w, r, http.StatusOK, err) +func (h *handler) WriteRequestError(ctx context.Context, w http.ResponseWriter, err error) error { + return courier.WriteError(ctx, w, http.StatusOK, err) } // GetChannel returns the channel diff --git a/handlers/i2sms/i2sms.go b/handlers/i2sms/i2sms.go index fe8e80baf..0cb2ae3c1 100644 --- a/handlers/i2sms/i2sms.go +++ b/handlers/i2sms/i2sms.go @@ -152,7 +152,7 @@ func (h *handler) RedactValues(ch courier.Channel) []string { } // WriteMsgSuccessResponse writes a success response for the messages, i2SMS expects an empty body in our response -func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error { +func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { w.Header().Add("Content-type", "text/plain") w.WriteHeader(http.StatusOK) _, err := w.Write([]byte{}) diff --git a/handlers/jasmin/jasmin.go b/handlers/jasmin/jasmin.go index 7d2077212..633c8d1fd 100644 --- a/handlers/jasmin/jasmin.go +++ b/handlers/jasmin/jasmin.go @@ -100,15 +100,15 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } -func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error { +func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { return writeJasminACK(w) } -func (h *handler) WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, statuses []courier.MsgStatus) error { +func (h *handler) WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, statuses []courier.MsgStatus) error { return writeJasminACK(w) } -func (h *handler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter, r *http.Request, details string) error { +func (h *handler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter, details string) error { return writeJasminACK(w) } diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index af9429473..39dcf51c6 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -135,7 +135,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return nil, err } - return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(ctx, w, r, channelEvent) + return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(ctx, w, channelEvent) } // unknown event type (we only deal with subscribe) diff --git a/handlers/m3tech/m3tech.go b/handlers/m3tech/m3tech.go index af93d1f2b..77967718c 100644 --- a/handlers/m3tech/m3tech.go +++ b/handlers/m3tech/m3tech.go @@ -62,7 +62,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. } // WriteMsgSuccessResponse writes a success response for the messages -func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error { +func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { w.Header().Set("Content-Type", "application/json") _, err := fmt.Fprintf(w, "SMS Accepted: %d", msgs[0].ID()) return err diff --git a/handlers/macrokiosk/macrokiosk.go b/handlers/macrokiosk/macrokiosk.go index 3561056e2..c318d0dcb 100644 --- a/handlers/macrokiosk/macrokiosk.go +++ b/handlers/macrokiosk/macrokiosk.go @@ -135,7 +135,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // WriteMsgSuccessResponse -func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error { +func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { w.WriteHeader(200) _, err := fmt.Fprint(w, "-1") // MacroKiosk expects "-1" back for successful requests return err diff --git a/handlers/mtarget/mtarget.go b/handlers/mtarget/mtarget.go index 78d1e626b..3bdc12da0 100644 --- a/handlers/mtarget/mtarget.go +++ b/handlers/mtarget/mtarget.go @@ -138,7 +138,7 @@ func (h *handler) receiveMsg(ctx context.Context, c courier.Channel, w http.Resp if err != nil { return nil, err } - return []courier.Event{stop}, courier.WriteChannelEventSuccess(ctx, w, r, stop) + return []courier.Event{stop}, courier.WriteChannelEventSuccess(ctx, w, stop) } // otherwise, create our incoming message and write that diff --git a/handlers/responses.go b/handlers/responses.go index b3bb1744f..2803f9e51 100644 --- a/handlers/responses.go +++ b/handlers/responses.go @@ -18,7 +18,7 @@ func WriteMsgsAndResponse(ctx context.Context, h courier.ChannelHandler, msgs [] events[i] = m } - return events, h.WriteMsgSuccessResponse(ctx, w, r, msgs) + return events, h.WriteMsgSuccessResponse(ctx, w, msgs) } // WriteMsgStatusAndResponse write the passed in status to our backend @@ -32,17 +32,17 @@ func WriteMsgStatusAndResponse(ctx context.Context, h courier.ChannelHandler, ch return nil, err } - return []courier.Event{status}, h.WriteStatusSuccessResponse(ctx, w, r, []courier.MsgStatus{status}) + return []courier.Event{status}, h.WriteStatusSuccessResponse(ctx, w, []courier.MsgStatus{status}) } // WriteAndLogRequestError logs the passed in error and writes the response to the response writer func WriteAndLogRequestError(ctx context.Context, h courier.ChannelHandler, channel courier.Channel, w http.ResponseWriter, r *http.Request, err error) error { courier.LogRequestError(r, channel, err) - return h.WriteRequestError(ctx, w, r, err) + return h.WriteRequestError(ctx, w, err) } // WriteAndLogRequestIgnored logs that the passed in request was ignored and writes the response to the response writer func WriteAndLogRequestIgnored(ctx context.Context, h courier.ChannelHandler, channel courier.Channel, w http.ResponseWriter, r *http.Request, details string) error { courier.LogRequestIgnored(r, channel, details) - return h.WriteRequestIgnored(ctx, w, r, details) + return h.WriteRequestIgnored(ctx, w, details) } diff --git a/handlers/start/start.go b/handlers/start/start.go index c58b83ed4..43f3a4372 100644 --- a/handlers/start/start.go +++ b/handlers/start/start.go @@ -89,7 +89,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // Start Mobile expects a XML response from a message receive request -func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error { +func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { w.Header().Set("Content-Type", "text/xml") w.WriteHeader(200) _, err := fmt.Fprint(w, `Accepted`) diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index 047a719ac..b22ee1247 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -83,7 +83,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w if err != nil { return nil, err } - return []courier.Event{event}, courier.WriteChannelEventSuccess(ctx, w, r, event) + return []courier.Event{event}, courier.WriteChannelEventSuccess(ctx, w, event) } // normal message of some kind diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index 0a8abed53..65a474a25 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -413,7 +413,7 @@ func twCalculateSignature(url string, form url.Values, authToken string) ([]byte } // WriteMsgSuccessResponse writes our response in TWIML format -func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error { +func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { w.Header().Set("Content-Type", "text/xml") w.WriteHeader(200) _, err := fmt.Fprint(w, ``) @@ -421,7 +421,7 @@ func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWr } // WriteRequestIgnored writes our response in TWIML format -func (h *handler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter, r *http.Request, details string) error { +func (h *handler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter, details string) error { w.Header().Set("Content-Type", "text/xml") w.WriteHeader(200) _, err := fmt.Fprintf(w, ``, details) diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index 5c406192d..2de8ecade 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -148,7 +148,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, err } - return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(ctx, w, r, channelEvent) + return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(ctx, w, channelEvent) case "unsubscribed": viberID := payload.UserID @@ -166,7 +166,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, err } - return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(ctx, w, r, channelEvent) + return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(ctx, w, channelEvent) case "failed": msgStatus := h.Backend().NewMsgStatusForExternalID(channel, fmt.Sprintf("%d", payload.MessageToken), courier.MsgFailed, clog) @@ -235,7 +235,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } - return nil, courier.WriteError(ctx, w, r, http.StatusBadRequest, fmt.Errorf("not handled, unknown event: %s", event)) + return nil, courier.WriteError(ctx, w, http.StatusBadRequest, fmt.Errorf("not handled, unknown event: %s", event)) } func writeWelcomeMessageResponse(w http.ResponseWriter, channel courier.Channel, event courier.Event) error { diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index 6be57fa94..c762a2f3f 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -194,7 +194,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return nil, err } - return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(ctx, w, r, channelEvent) + return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(ctx, w, channelEvent) } // unknown event type (we only deal with subscribe) @@ -214,7 +214,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // WriteMsgSuccessResponse writes our response -func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []courier.Msg) error { +func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { w.WriteHeader(200) _, err := fmt.Fprint(w, "") // WeChat expected empty string to not retry looking for passive reply return err diff --git a/responses.go b/responses.go index 10dd59fea..346b7f009 100644 --- a/responses.go +++ b/responses.go @@ -15,11 +15,11 @@ import ( // writeAndLogRequestError writes a JSON response for the passed in message and logs an info messages func writeAndLogRequestError(ctx context.Context, h ChannelHandler, w http.ResponseWriter, r *http.Request, c Channel, err error) error { LogRequestError(r, c, err) - return h.WriteRequestError(ctx, w, r, err) + return h.WriteRequestError(ctx, w, err) } // WriteError writes a JSON response for the passed in error -func WriteError(ctx context.Context, w http.ResponseWriter, r *http.Request, statusCode int, err error) error { +func WriteError(ctx context.Context, w http.ResponseWriter, statusCode int, err error) error { errors := []interface{}{NewErrorData(err.Error())} vErrs, isValidation := err.(validator.ValidationErrors) @@ -32,7 +32,7 @@ func WriteError(ctx context.Context, w http.ResponseWriter, r *http.Request, sta } // WriteIgnored writes a JSON response indicating that we ignored the request -func WriteIgnored(ctx context.Context, w http.ResponseWriter, r *http.Request, details string) error { +func WriteIgnored(ctx context.Context, w http.ResponseWriter, details string) error { return WriteDataResponse(ctx, w, http.StatusOK, "Ignored", []interface{}{NewInfoData(details)}) } @@ -43,12 +43,12 @@ func WriteAndLogUnauthorized(ctx context.Context, w http.ResponseWriter, r *http } // WriteChannelEventSuccess writes a JSON response for the passed in event indicating we handled it -func WriteChannelEventSuccess(ctx context.Context, w http.ResponseWriter, r *http.Request, event ChannelEvent) error { +func WriteChannelEventSuccess(ctx context.Context, w http.ResponseWriter, event ChannelEvent) error { return WriteDataResponse(ctx, w, http.StatusOK, "Event Accepted", []interface{}{NewEventReceiveData(event)}) } // WriteMsgSuccess writes a JSON response for the passed in msg indicating we handled it -func WriteMsgSuccess(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []Msg) error { +func WriteMsgSuccess(ctx context.Context, w http.ResponseWriter, msgs []Msg) error { data := []interface{}{} for _, msg := range msgs { data = append(data, NewMsgReceiveData(msg)) @@ -58,7 +58,7 @@ func WriteMsgSuccess(ctx context.Context, w http.ResponseWriter, r *http.Request } // WriteStatusSuccess writes a JSON response for the passed in status update indicating we handled it -func WriteStatusSuccess(ctx context.Context, w http.ResponseWriter, r *http.Request, statuses []MsgStatus) error { +func WriteStatusSuccess(ctx context.Context, w http.ResponseWriter, statuses []MsgStatus) error { data := []interface{}{} for _, status := range statuses { data = append(data, NewStatusData(status)) diff --git a/responses_test.go b/responses_test.go new file mode 100644 index 000000000..58a3a5d5e --- /dev/null +++ b/responses_test.go @@ -0,0 +1,70 @@ +package courier_test + +import ( + "context" + "errors" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/nyaruka/courier" + "github.com/nyaruka/courier/test" + "github.com/stretchr/testify/assert" +) + +func TestWriteError(t *testing.T) { + ctx := context.Background() + w := httptest.NewRecorder() + + err := courier.WriteError(ctx, w, 406, errors.New("boom")) + assert.NoError(t, err) + assert.Equal(t, 406, w.Code) + assert.Equal(t, "{\"message\":\"Error\",\"data\":[{\"type\":\"error\",\"error\":\"boom\"}]}\n", w.Body.String()) +} + +func TestWriteIgnored(t *testing.T) { + ctx := context.Background() + w := httptest.NewRecorder() + + err := courier.WriteIgnored(ctx, w, "why you calling") + assert.NoError(t, err) + assert.Equal(t, 200, w.Code) + assert.Equal(t, "{\"message\":\"Ignored\",\"data\":[{\"type\":\"info\",\"info\":\"why you calling\"}]}\n", w.Body.String()) +} + +func TestWriteAndLogUnauthorized(t *testing.T) { + ctx := context.Background() + ch := test.NewMockChannel("5fccf4b6-48d7-4f5a-bce8-b0d1fd5342ec", "NX", "+1234567890", "US", nil) + r, _ := http.NewRequest("GET", "http://example.com", nil) + w := httptest.NewRecorder() + + err := courier.WriteAndLogUnauthorized(ctx, w, r, ch, errors.New("wrong password")) + assert.NoError(t, err) + assert.Equal(t, 401, w.Code) + assert.Equal(t, "{\"message\":\"Unauthorized\",\"data\":[{\"type\":\"error\",\"error\":\"wrong password\"}]}\n", w.Body.String()) +} + +func TestWriteMsgSuccess(t *testing.T) { + ctx := context.Background() + ch := test.NewMockChannel("5fccf4b6-48d7-4f5a-bce8-b0d1fd5342ec", "NX", "+1234567890", "US", nil) + msg := test.NewMockBackend().NewIncomingMsg(ch, "tel:+0987654321", "hi there", nil).WithUUID(courier.NewMsgUUIDFromString("588aafc4-ab5c-48ce-89e8-05c9fdeeafb7")) + w := httptest.NewRecorder() + + err := courier.WriteMsgSuccess(ctx, w, []courier.Msg{msg}) + assert.NoError(t, err) + assert.Equal(t, 200, w.Code) + assert.Equal(t, "{\"message\":\"Message Accepted\",\"data\":[{\"type\":\"msg\",\"channel_uuid\":\"5fccf4b6-48d7-4f5a-bce8-b0d1fd5342ec\",\"msg_uuid\":\"588aafc4-ab5c-48ce-89e8-05c9fdeeafb7\",\"text\":\"hi there\",\"urn\":\"tel:+0987654321\"}]}\n", w.Body.String()) +} + +func TestWriteChannelEventSuccess(t *testing.T) { + ctx := context.Background() + ch := test.NewMockChannel("5fccf4b6-48d7-4f5a-bce8-b0d1fd5342ec", "NX", "+1234567890", "US", nil) + evt := test.NewMockBackend().NewChannelEvent(ch, courier.StopContact, "tel:+0987654321", nil).WithOccurredOn(time.Date(2022, 9, 15, 12, 7, 30, 0, time.UTC)) + w := httptest.NewRecorder() + + err := courier.WriteChannelEventSuccess(ctx, w, evt) + assert.NoError(t, err) + assert.Equal(t, 200, w.Code) + assert.Equal(t, "{\"message\":\"Event Accepted\",\"data\":[{\"type\":\"event\",\"channel_uuid\":\"5fccf4b6-48d7-4f5a-bce8-b0d1fd5342ec\",\"event_type\":\"stop_contact\",\"urn\":\"tel:+0987654321\",\"received_on\":\"2022-09-15T12:07:30Z\"}]}\n", w.Body.String()) +} From 694618a680eea6842d5960d1466e9da546be0e45 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 15 Sep 2022 13:04:38 -0500 Subject: [PATCH 173/294] Update CHANGELOG.md for v7.5.29 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6a8a3050..49e0f0c47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.29 +---------- + * Simplify constructing responses and add tests + * Make it easier to override responses per handler + v7.5.28 ---------- * Update to use SHA256 signature for FBA payload, increase max body bytes limit to 1MiB From c9134d9ed2caee5509fc2356cba42c26e6546b90 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 16 Sep 2022 12:13:11 -0700 Subject: [PATCH 174/294] Update LICENSE --- LICENSE | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/LICENSE b/LICENSE index dbbe35581..7804467b6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,19 @@ +Courier - messaging gateway for text-based messaging channels. + +Copyright (C) 2007-2022 TextIt. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License below for more details. + +------------------------------------------------------------------------ + GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 From e0eae0f571a2a77e6ac85285a128e053f398840b Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 16 Sep 2022 12:35:13 -0700 Subject: [PATCH 175/294] Update LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 7804467b6..85d3ba030 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Courier - messaging gateway for text-based messaging channels. +Courier - messaging gateway for the TextIt platform. Copyright (C) 2007-2022 TextIt. From 0f5165dd5bab5312c93b982f2c14b4e40c9126d0 Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Fri, 16 Sep 2022 15:25:52 -0700 Subject: [PATCH 176/294] Create cla.yml --- .github/workflows/cla.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/cla.yml diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml new file mode 100644 index 000000000..0fdd28f83 --- /dev/null +++ b/.github/workflows/cla.yml @@ -0,0 +1,25 @@ +name: "CLA Assistant" +on: + issue_comment: + types: [created] + pull_request_target: + types: [opened,closed,synchronize] + +jobs: + CLAssistant: + runs-on: ubuntu-latest + steps: + - name: "CLA Assistant" + if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' + # Beta Release + uses: contributor-assistant/github-action@v2.2.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PERSONAL_ACCESS_TOKEN : ${{ secrets.CLA_TOKEN }} + with: + path-to-signatures: 'signatures/version1/cla.json' + path-to-document: 'https://github.com/nyaruka/legal/blob/main/TextIt%20CLA.md' + branch: 'main' + allowlist: bot* + remote-organization-name: 'nyaruka' + remote-repository-name: 'legal' From 57e40395636295a5f7e2040e46734d6526f4e436 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 19 Sep 2022 14:41:04 -0500 Subject: [PATCH 177/294] Update msg status updating to allow skipping WIRED state --- backends/rapidpro/backend_test.go | 101 +++++++++++++++--------------- backends/rapidpro/status.go | 26 ++++---- 2 files changed, 65 insertions(+), 62 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 970b7d495..55d5c2726 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -517,21 +517,35 @@ func (ts *BackendTestSuite) TestMsgStatus() { ctx := context.Background() channel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") now := time.Now().In(time.UTC) - time.Sleep(2 * time.Millisecond) + + updateStatusByID := func(id courier.MsgID, status courier.MsgStatusValue, newExtID string) *courier.ChannelLog { + clog := courier.NewChannelLog(courier.ChannelLogTypeMsgStatus, channel, nil) + statusObj := ts.b.NewMsgStatusForID(channel, id, status, clog) + if newExtID != "" { + statusObj.SetExternalID(newExtID) + } + err := ts.b.WriteMsgStatus(ctx, statusObj) + ts.NoError(err) + time.Sleep(500 * time.Millisecond) // give committer time to write this + return clog + } + + updateStatusByExtID := func(extID string, status courier.MsgStatusValue) *courier.ChannelLog { + clog := courier.NewChannelLog(courier.ChannelLogTypeMsgStatus, channel, nil) + statusObj := ts.b.NewMsgStatusForExternalID(channel, extID, status, clog) + err := ts.b.WriteMsgStatus(ctx, statusObj) + ts.NoError(err) + time.Sleep(500 * time.Millisecond) // give committer time to write this + return clog + } // put test message back into queued state ts.b.db.MustExec(`UPDATE msgs_msg SET status = 'Q', sent_on = NULL WHERE id = $1`, 10001) // update to WIRED using id and provide new external ID - clog1 := courier.NewChannelLog(courier.ChannelLogTypeMsgStatus, channel, nil) - status := ts.b.NewMsgStatusForID(channel, courier.NewMsgID(10001), courier.MsgWired, clog1) - status.SetExternalID("ext0") - err := ts.b.WriteMsgStatus(ctx, status) - ts.NoError(err) + clog1 := updateStatusByID(10001, courier.MsgWired, "ext0") - time.Sleep(time.Second) // give committer time to write this - - m := readMsgFromDB(ts.b, courier.NewMsgID(10001)) + m := readMsgFromDB(ts.b, 10001) ts.Equal(courier.MsgWired, m.Status_) ts.Equal(null.String("ext0"), m.ExternalID_) ts.True(m.ModifiedOn_.After(now)) @@ -542,14 +556,9 @@ func (ts *BackendTestSuite) TestMsgStatus() { sentOn := *m.SentOn_ // update to SENT using id - clog2 := courier.NewChannelLog(courier.ChannelLogTypeMsgStatus, channel, nil) - status = ts.b.NewMsgStatusForID(channel, courier.NewMsgID(10001), courier.MsgSent, clog2) - err = ts.b.WriteMsgStatus(ctx, status) - ts.NoError(err) - - time.Sleep(time.Second) // give committer time to write this + clog2 := updateStatusByID(10001, courier.MsgSent, "") - m = readMsgFromDB(ts.b, courier.NewMsgID(10001)) + m = readMsgFromDB(ts.b, 10001) ts.Equal(courier.MsgSent, m.Status_) ts.Equal(null.String("ext0"), m.ExternalID_) // no change ts.True(m.ModifiedOn_.After(now)) @@ -557,55 +566,38 @@ func (ts *BackendTestSuite) TestMsgStatus() { ts.Equal(pq.StringArray([]string{string(clog1.UUID()), string(clog2.UUID())}), m.LogUUIDs) // update to DELIVERED using id - clog3 := courier.NewChannelLog(courier.ChannelLogTypeMsgStatus, channel, nil) - status = ts.b.NewMsgStatusForID(channel, courier.NewMsgID(10001), courier.MsgDelivered, clog3) - err = ts.b.WriteMsgStatus(ctx, status) - ts.NoError(err) - time.Sleep(time.Second) + clog3 := updateStatusByID(10001, courier.MsgDelivered, "") - m = readMsgFromDB(ts.b, courier.NewMsgID(10001)) + m = readMsgFromDB(ts.b, 10001) ts.Equal(m.Status_, courier.MsgDelivered) ts.True(m.ModifiedOn_.After(now)) ts.True(m.SentOn_.Equal(sentOn)) // no change ts.Equal(pq.StringArray([]string{string(clog1.UUID()), string(clog2.UUID()), string(clog3.UUID())}), m.LogUUIDs) // no change for incoming messages - clog4 := courier.NewChannelLog(courier.ChannelLogTypeMsgStatus, channel, nil) - status = ts.b.NewMsgStatusForID(channel, courier.NewMsgID(10002), courier.MsgSent, clog4) - err = ts.b.WriteMsgStatus(ctx, status) - ts.NoError(err) - - time.Sleep(time.Second) // give committer time to write this + updateStatusByID(10002, courier.MsgSent, "") - m = readMsgFromDB(ts.b, courier.NewMsgID(10002)) + m = readMsgFromDB(ts.b, 10002) ts.Equal(courier.MsgPending, m.Status_) ts.Equal(m.ExternalID_, null.String("ext2")) ts.Equal(pq.StringArray(nil), m.LogUUIDs) // update to FAILED using external id - clog5 := courier.NewChannelLog(courier.ChannelLogTypeMsgStatus, channel, nil) - status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgFailed, clog5) - err = ts.b.WriteMsgStatus(ctx, status) - ts.NoError(err) - time.Sleep(time.Second) + clog5 := updateStatusByExtID("ext1", courier.MsgFailed) - m = readMsgFromDB(ts.b, courier.NewMsgID(10000)) + m = readMsgFromDB(ts.b, 10000) ts.Equal(courier.MsgFailed, m.Status_) ts.True(m.ModifiedOn_.After(now)) ts.Nil(m.SentOn_) + ts.Equal(pq.StringArray([]string{string(clog5.UUID())}), m.LogUUIDs) now = time.Now().In(time.UTC) time.Sleep(2 * time.Millisecond) // update to WIRED using external id - clog6 := courier.NewChannelLog(courier.ChannelLogTypeMsgStatus, channel, nil) - status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgWired, clog6) - err = ts.b.WriteMsgStatus(ctx, status) - ts.NoError(err) - - time.Sleep(time.Second) // give committer time to write this + clog6 := updateStatusByExtID("ext1", courier.MsgWired) - m = readMsgFromDB(ts.b, courier.NewMsgID(10000)) + m = readMsgFromDB(ts.b, 10000) ts.Equal(courier.MsgWired, m.Status_) ts.True(m.ModifiedOn_.After(now)) ts.True(m.SentOn_.After(now)) @@ -613,19 +605,30 @@ func (ts *BackendTestSuite) TestMsgStatus() { sentOn = *m.SentOn_ // update to SENT using external id - status = ts.b.NewMsgStatusForExternalID(channel, "ext1", courier.MsgSent, clog6) - err = ts.b.WriteMsgStatus(ctx, status) - ts.NoError(err) - time.Sleep(time.Second) + updateStatusByExtID("ext1", courier.MsgSent) - m = readMsgFromDB(ts.b, courier.NewMsgID(10000)) + m = readMsgFromDB(ts.b, 10000) ts.Equal(courier.MsgSent, m.Status_) ts.True(m.ModifiedOn_.After(now)) ts.True(m.SentOn_.Equal(sentOn)) // no change + // put test outgoing messages back into queued state + ts.b.db.MustExec(`UPDATE msgs_msg SET status = 'Q', sent_on = NULL WHERE id IN ($1, $2)`, 10002, 10001) + + // can skip WIRED and go straight to SENT or DELIVERED + updateStatusByExtID("ext1", courier.MsgSent) + updateStatusByID(10001, courier.MsgDelivered, "") + + m = readMsgFromDB(ts.b, 10000) + ts.Equal(courier.MsgSent, m.Status_) + ts.NotNil(m.SentOn_) + m = readMsgFromDB(ts.b, 10001) + ts.Equal(courier.MsgDelivered, m.Status_) + ts.NotNil(m.SentOn_) + // no such external id for outgoing message - status = ts.b.NewMsgStatusForExternalID(channel, "ext2", courier.MsgSent, clog6) - err = ts.b.WriteMsgStatus(ctx, status) + status := ts.b.NewMsgStatusForExternalID(channel, "ext2", courier.MsgSent, clog6) + err := ts.b.WriteMsgStatus(ctx, status) ts.Error(err) // no such external id diff --git a/backends/rapidpro/status.go b/backends/rapidpro/status.go index ed78aed26..e75eb8114 100644 --- a/backends/rapidpro/status.go +++ b/backends/rapidpro/status.go @@ -116,12 +116,12 @@ UPDATE msgs_msg SET failed_reason END, sent_on = CASE - WHEN - :status = 'W' - THEN - NOW() - ELSE - sent_on + WHEN + :status IN ('W', 'S', 'D') + THEN + COALESCE(sent_on, NOW()) + ELSE + NULL END, external_id = CASE WHEN @@ -182,12 +182,12 @@ UPDATE msgs_msg SET failed_reason END, sent_on = CASE - WHEN + WHEN :status IN ('W', 'S', 'D') - THEN + THEN COALESCE(sent_on, NOW()) - ELSE - NULL + ELSE + NULL END, modified_on = :modified_on, log_uuids = array_append(log_uuids, :log_uuid) @@ -282,11 +282,11 @@ UPDATE msgs_msg SET next_attempt END, sent_on = CASE - WHEN + WHEN s.status IN ('W', 'S', 'D') - THEN + THEN COALESCE(sent_on, NOW()) - ELSE + ELSE NULL END, external_id = CASE From db03caa6bf75cc603ce288994578b0193e4af420 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 20 Sep 2022 10:47:59 -0500 Subject: [PATCH 178/294] Update CHANGELOG.md for v7.5.30 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49e0f0c47..a98e59fb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.30 +---------- + * Update msg status updating to allow skipping WIRED state + v7.5.29 ---------- * Simplify constructing responses and add tests From 3f0a3d3496a0c72fd8753a54138dffd1633609bb Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 21 Sep 2022 14:52:25 -0500 Subject: [PATCH 179/294] Allow twiml channels to send multiple media urls per message --- handlers/test.go | 8 +++++++- handlers/twiml/twiml.go | 22 ++++++++++++++++++---- handlers/twiml/twiml_test.go | 31 +++++++++++++++++++++++++++---- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/handlers/test.go b/handlers/test.go index 1d009b0a8..4022f40bb 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -9,6 +9,7 @@ import ( "mime/multipart" "net/http" "net/http/httptest" + "net/url" "strings" "testing" "time" @@ -269,7 +270,8 @@ type ChannelSendTestCase struct { ExpectedRequestPath string ExpectedURLParams map[string]string - ExpectedPostParams map[string]string + ExpectedPostParams map[string]string // deprecated, use ExpectedPostForm + ExpectedPostForm url.Values ExpectedRequestBody string ExpectedHeaders map[string]string ExpectedMsgStatus courier.MsgStatusValue @@ -372,6 +374,10 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour value := testRequest.PostFormValue(k) require.Equal(v, value) } + } else if tc.ExpectedPostForm != nil { + require.NotNil(testRequest, "post body should not be nil") + testRequest.ParseMultipartForm(32 << 20) + assert.Equal(t, tc.ExpectedPostForm, testRequest.PostForm) } if tc.ExpectedRequestBody != "" { diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index 65a474a25..4ee928087 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -43,6 +43,14 @@ var ( twilioBaseURL = "https://api.twilio.com" ) +// see https://www.twilio.com/docs/sms/accepted-mime-types#accepted-mime-types +var mediaSupport = map[handlers.MediaType]handlers.MediaTypeSupport{ + handlers.MediaTypeImage: {MaxBytes: 5 * 1024 * 1024}, + handlers.MediaTypeAudio: {MaxBytes: 5 * 1024 * 1024}, + handlers.MediaTypeVideo: {MaxBytes: 5 * 1024 * 1024}, + handlers.MediaTypeApplication: {MaxBytes: 5 * 1024 * 1024}, +} + // error code twilio returns when a contact has sent "stop" const errorStopped = 21610 @@ -217,6 +225,11 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann channel := msg.Channel() + attachments, err := handlers.ResolveAttachments(ctx, h.Backend(), msg.Attachments(), mediaSupport, true) + if err != nil { + return nil, errors.Wrap(err, "error resolving attachments") + } + status := h.Backend().NewMsgStatusForID(channel, msg.ID(), courier.MsgErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), msg.Text(), maxMsgLength) for i, part := range parts { @@ -227,10 +240,11 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann "StatusCallback": []string{callbackURL}, } - // add any media URL to the first part - if len(msg.Attachments()) > 0 && i == 0 { - _, mediaURL := handlers.SplitAttachment(msg.Attachments()[0]) - form["MediaUrl"] = []string{mediaURL} + // add any attachments to the first part + if i == 0 { + for _, a := range attachments { + form.Add("MediaUrl", a.URL) + } } // set our from, either as a messaging service or from our address diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index 8031fb5d8..859b9d622 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -3,6 +3,7 @@ package twiml import ( "net/http" "net/http/httptest" + "net/url" "testing" "fmt" @@ -364,15 +365,37 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL, }, { - Label: "Send Attachment", + Label: "Single attachment and text", MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, MockResponseBody: `{ "sid": "1002" }`, MockResponseStatus: 200, - ExpectedPostParams: map[string]string{"Body": "My pic!", "To": "+250788383383", "MediaUrl": "https://foo.bar/image.jpg", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, - ExpectedMsgStatus: "W", - SendPrep: setSendURL, + ExpectedPostForm: url.Values{ + "Body": []string{"My pic!"}, + "To": []string{"+250788383383"}, + "MediaUrl": []string{"https://foo.bar/image.jpg"}, + "From": []string{"2020"}, + "StatusCallback": []string{"https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + }, + ExpectedMsgStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Multiple attachments, no text", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg", "audio/mp4:https://foo.bar/audio.m4a"}, + MockResponseBody: `{ "sid": "1002" }`, + MockResponseStatus: 200, + ExpectedPostForm: url.Values{ + "Body": []string{""}, + "To": []string{"+250788383383"}, + "MediaUrl": []string{"https://foo.bar/image.jpg", "https://foo.bar/audio.m4a"}, + "From": []string{"2020"}, + "StatusCallback": []string{"https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, + }, + ExpectedMsgStatus: "W", + SendPrep: setSendURL, }, } From 8499e8b9cd0cba6efd6614752a3d85fae2a8f1d9 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 21 Sep 2022 15:16:42 -0500 Subject: [PATCH 180/294] Update CHANGELOG.md for v7.5.31 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a98e59fb7..9fbda062b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.31 +---------- + * Allow twiml channels to send multiple media urls per message + v7.5.30 ---------- * Update msg status updating to allow skipping WIRED state From 45ed4718886a81f18f36a953b20a9b5b452431c6 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 22 Sep 2022 10:45:15 -0500 Subject: [PATCH 181/294] Add support for better channel error reporting --- backends/rapidpro/backend_test.go | 2 +- backends/rapidpro/msg.go | 2 +- channel_log.go | 40 ++++++++++++++++++++---- channel_log_test.go | 21 ++++++++++--- handler_test.go | 4 +-- handlers/arabiacell/arabiacell.go | 4 +-- handlers/arabiacell/arabiacell_test.go | 4 +-- handlers/blackmyna/blackmyna_test.go | 2 +- handlers/burstsms/burstsms.go | 4 +-- handlers/burstsms/burstsms_test.go | 4 +-- handlers/clickatell/clickatell.go | 2 +- handlers/clickatell/clickatell_test.go | 2 +- handlers/clickmobile/clickmobile.go | 2 +- handlers/clicksend/clicksend.go | 4 +-- handlers/clicksend/clicksend_test.go | 2 +- handlers/dart/dart.go | 19 +++++------ handlers/dart/dart_test.go | 4 +-- handlers/dmark/dmark.go | 2 +- handlers/dmark/dmark_test.go | 2 +- handlers/external/external.go | 2 +- handlers/external/external_test.go | 2 +- handlers/facebook/facebook.go | 16 +++++----- handlers/facebook/facebook_test.go | 2 +- handlers/facebookapp/facebookapp.go | 18 +++++------ handlers/facebookapp/facebookapp_test.go | 6 ++-- handlers/firebase/firebase.go | 4 +-- handlers/firebase/firebase_test.go | 4 +-- handlers/freshchat/freshchat.go | 2 +- handlers/i2sms/i2sms.go | 4 +-- handlers/i2sms/i2sms_test.go | 4 +-- handlers/infobip/infobip.go | 2 +- handlers/infobip/infobip_test.go | 2 +- handlers/jiochat/jiochat.go | 2 +- handlers/junebug/junebug.go | 2 +- handlers/junebug/junebug_test.go | 4 +-- handlers/kaleyra/kaleyra.go | 6 ++-- handlers/macrokiosk/macrokiosk_test.go | 2 +- handlers/mblox/mblox_test.go | 2 +- handlers/messangi/messangi.go | 4 +-- handlers/messangi/messangi_test.go | 2 +- handlers/mtarget/mtarget.go | 2 +- handlers/mtarget/mtarget_test.go | 2 +- handlers/nexmo/nexmo.go | 2 +- handlers/nexmo/nexmo_test.go | 4 +-- handlers/novo/novo.go | 2 +- handlers/novo/novo_test.go | 4 +-- handlers/plivo/plivo_test.go | 2 +- handlers/slack/slack.go | 6 ++-- handlers/slack/slack_test.go | 2 +- handlers/telegram/telegram.go | 2 +- handlers/telegram/telegram_test.go | 2 +- handlers/telesom/telesom.go | 2 +- handlers/test.go | 4 +-- handlers/thinq/thinq.go | 4 +-- handlers/thinq/thinq_test.go | 2 +- handlers/twiml/twiml.go | 4 +-- handlers/twiml/twiml_test.go | 32 +++++++++---------- handlers/twitter/twitter.go | 6 ++-- handlers/twitter/twitter_test.go | 4 +-- handlers/viber/viber.go | 6 ++-- handlers/viber/viber_test.go | 6 ++-- handlers/vk/vk.go | 2 +- handlers/wechat/wechat.go | 2 +- handlers/whatsapp/whatsapp.go | 4 +-- handlers/whatsapp/whatsapp_test.go | 2 +- handlers/zenvia/zenvia.go | 2 +- handlers/zenvia/zenvia_test.go | 4 +-- handlers/zenviaold/zenviaold.go | 2 +- handlers/zenviaold/zenviaold_test.go | 2 +- sender.go | 2 +- 70 files changed, 191 insertions(+), 149 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 55d5c2726..0732d1c8c 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -1003,7 +1003,7 @@ func (ts *BackendTestSuite) TestWriteChanneLog() { clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel, nil) clog.HTTP(trace) - clog.Error(errors.New("this is an error")) + clog.RawError(errors.New("this is an error")) err = ts.b.WriteChannelLog(ctx, clog) ts.NoError(err) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index fc7753741..9af4eeafd 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -73,7 +73,7 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch } else if strings.HasPrefix(attURL, "data:") { attData, err := base64.StdEncoding.DecodeString(attURL[5:]) if err != nil { - clog.Error(errors.New("unable to decode attachment data")) + clog.Error(courier.NewChannelError("Unable to decode attachment data.", "")) return errors.Wrap(err, "unable to decode attachment data") } diff --git a/channel_log.go b/channel_log.go index 33ff124ba..4c220ae03 100644 --- a/channel_log.go +++ b/channel_log.go @@ -1,6 +1,7 @@ package courier import ( + "fmt" "time" "github.com/nyaruka/gocommon/dates" @@ -30,8 +31,31 @@ type ChannelError struct { code string } -func NewChannelError(message, code string) ChannelError { - return ChannelError{message: message, code: code} +func NewChannelError(message, code string) *ChannelError { + return &ChannelError{message: message, code: code} +} + +func ErrorResponseStatusCode() *ChannelError { + return NewChannelError("Unexpected response status code.", "core:response_status_code") +} + +func ErrorResponseUnparseable(format string) *ChannelError { + return NewChannelError(fmt.Sprintf("Unable to parse response as %s.", format), "core:response_unparseable") +} + +func ErrorUnsupportedMedia(contentType string) *ChannelError { + return NewChannelError(fmt.Sprintf("Unsupported attachment media type: %s.", contentType), "core:media_unsupported_type") +} + +func ErrorServiceSpecific(ns, code, message string) *ChannelError { + if message == "" { + message = fmt.Sprintf("Service specific error: %s.", code) + } + return NewChannelError(message, fmt.Sprintf("%s:%s", ns, code)) +} + +func (e *ChannelError) Redact(r stringsx.Redactor) *ChannelError { + return &ChannelError{message: r(e.message), code: r(e.code)} } func (e *ChannelError) Message() string { @@ -49,7 +73,7 @@ type ChannelLog struct { channel Channel msgID MsgID httpLogs []*httpx.Log - errors []ChannelError + errors []*ChannelError createdOn time.Time elapsed time.Duration @@ -91,8 +115,12 @@ func (l *ChannelLog) HTTP(t *httpx.Trace) { l.httpLogs = append(l.httpLogs, l.traceToLog(t)) } -func (l *ChannelLog) Error(err error) { - l.errors = append(l.errors, NewChannelError(l.redactor(err.Error()), "")) +func (l *ChannelLog) Error(e *ChannelError) { + l.errors = append(l.errors, e) +} + +func (l *ChannelLog) RawError(err error) { + l.Error(NewChannelError(err.Error(), "")) } func (l *ChannelLog) End() { @@ -132,7 +160,7 @@ func (l *ChannelLog) HTTPLogs() []*httpx.Log { return l.httpLogs } -func (l *ChannelLog) Errors() []ChannelError { +func (l *ChannelLog) Errors() []*ChannelError { return l.errors } diff --git a/channel_log_test.go b/channel_log_test.go index 776ca674c..1b91aaf74 100644 --- a/channel_log_test.go +++ b/channel_log_test.go @@ -41,7 +41,8 @@ func TestChannelLog(t *testing.T) { assert.EqualError(t, err, "unable to connect to server") clog.HTTP(trace) - clog.Error(errors.New("this is an error")) + clog.Error(courier.NewChannelError("Something not right", "twilio:23456")) + clog.RawError(errors.New("this is an error")) clog.End() assert.Equal(t, courier.ChannelLogUUID("c00e5d67-c275-4389-aded-7d8b151cbd5b"), clog.UUID()) @@ -49,7 +50,7 @@ func TestChannelLog(t *testing.T) { assert.Equal(t, channel, clog.Channel()) assert.Equal(t, courier.NilMsgID, clog.MsgID()) assert.Equal(t, 2, len(clog.HTTPLogs())) - assert.Equal(t, 1, len(clog.Errors())) + assert.Equal(t, 2, len(clog.Errors())) assert.False(t, clog.CreatedOn().IsZero()) assert.Greater(t, clog.Elapsed(), time.Duration(0)) @@ -65,8 +66,12 @@ func TestChannelLog(t *testing.T) { assert.Equal(t, "", hlog2.Response) err1 := clog.Errors()[0] - assert.Equal(t, "this is an error", err1.Message()) - assert.Equal(t, "", err1.Code()) + assert.Equal(t, "Something not right", err1.Message()) + assert.Equal(t, "twilio:23456", err1.Code()) + + err2 := clog.Errors()[1] + assert.Equal(t, "this is an error", err2.Message()) + assert.Equal(t, "", err2.Code()) clog.SetMsgID(courier.NewMsgID(123)) clog.SetType(courier.ChannelLogTypeEventReceive) @@ -74,3 +79,11 @@ func TestChannelLog(t *testing.T) { assert.Equal(t, courier.NewMsgID(123), clog.MsgID()) assert.Equal(t, courier.ChannelLogTypeEventReceive, clog.Type()) } + +func TestChannelErrors(t *testing.T) { + assert.Equal(t, courier.NewChannelError("Unexpected response status code.", "core:response_status_code"), courier.ErrorResponseStatusCode()) + assert.Equal(t, courier.NewChannelError("Unable to parse response as FOO.", "core:response_unparseable"), courier.ErrorResponseUnparseable("FOO")) + assert.Equal(t, courier.NewChannelError("Unsupported attachment media type: image/tiff.", "core:media_unsupported_type"), courier.ErrorUnsupportedMedia("image/tiff")) + assert.Equal(t, courier.NewChannelError("Invalid FriendlyName.", "twilio:20002"), courier.ErrorServiceSpecific("twilio", "20002", "Invalid FriendlyName.")) + assert.Equal(t, courier.NewChannelError("Service specific error: 20003.", "twilio:20003"), courier.ErrorServiceSpecific("twilio", "20003", "")) +} diff --git a/handler_test.go b/handler_test.go index 95dfa48a2..caa93b35f 100644 --- a/handler_test.go +++ b/handler_test.go @@ -56,7 +56,7 @@ func (h *dummyHandler) Send(ctx context.Context, msg courier.Msg, clog *courier. clog.HTTP(trace) // log an error than contains a value that should be redacted - clog.Error(errors.New("contains sesame seeds")) + clog.RawError(errors.New("contains sesame seeds")) return h.backend.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgSent, clog), nil } @@ -154,7 +154,7 @@ func TestHandling(t *testing.T) { assert.Len(mb.WrittenChannelLogs(), 1) clog := mb.WrittenChannelLogs()[0] - assert.Equal([]courier.ChannelError{courier.NewChannelError("contains ********** seeds", "")}, clog.Errors()) + assert.Equal([]*courier.ChannelError{courier.NewChannelError("contains ********** seeds", "")}, clog.Errors()) assert.Len(clog.HTTPLogs(), 1) diff --git a/handlers/arabiacell/arabiacell.go b/handlers/arabiacell/arabiacell.go index 57623d9be..2ed0c2bdc 100644 --- a/handlers/arabiacell/arabiacell.go +++ b/handlers/arabiacell/arabiacell.go @@ -105,7 +105,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann response := &mtResponse{} err = xml.Unmarshal(respBody, response) if err != nil { - clog.Error(err) + clog.Error(courier.ErrorResponseUnparseable("XML")) break } @@ -115,7 +115,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann status.SetExternalID(response.MessageID) } else { status.SetStatus(courier.MsgFailed) - clog.Error(fmt.Errorf("Received invalid response code: %s", response.Code)) + clog.Error(courier.ErrorResponseStatusCode()) break } } diff --git a/handlers/arabiacell/arabiacell_test.go b/handlers/arabiacell/arabiacell_test.go index 788095c0b..229cc6992 100644 --- a/handlers/arabiacell/arabiacell_test.go +++ b/handlers/arabiacell/arabiacell_test.go @@ -80,7 +80,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `not xml`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("EOF", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("EOF", "")}, SendPrep: setSendURL, }, { @@ -90,7 +90,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `501failure`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid response code: 501", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Received invalid response code: 501", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/blackmyna/blackmyna_test.go b/handlers/blackmyna/blackmyna_test.go index 5730f74d0..8881fc404 100644 --- a/handlers/blackmyna/blackmyna_test.go +++ b/handlers/blackmyna/blackmyna_test.go @@ -122,7 +122,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 200, - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("no external id returned in body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("no external id returned in body", "")}, ExpectedPostParams: map[string]string{"message": `No External ID`, "address": "+250788383383", "senderaddress": "2020"}, ExpectedMsgStatus: "E", SendPrep: setSendURL, diff --git a/handlers/burstsms/burstsms.go b/handlers/burstsms/burstsms.go index 8b6d98476..0ab3e5fe5 100644 --- a/handlers/burstsms/burstsms.go +++ b/handlers/burstsms/burstsms.go @@ -93,7 +93,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann response := &mtResponse{} err = json.Unmarshal(respBody, response) if err != nil { - clog.Error(err) + clog.Error(courier.ErrorResponseUnparseable("XML")) break } @@ -102,7 +102,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann status.SetExternalID(fmt.Sprintf("%d", response.MessageID)) } else { status.SetStatus(courier.MsgFailed) - clog.Error(fmt.Errorf("Received invalid message id: %d", response.MessageID)) + clog.RawError(fmt.Errorf("Received invalid message id: %d", response.MessageID)) break } } diff --git a/handlers/burstsms/burstsms_test.go b/handlers/burstsms/burstsms_test.go index e41a887a6..948b997dc 100644 --- a/handlers/burstsms/burstsms_test.go +++ b/handlers/burstsms/burstsms_test.go @@ -86,7 +86,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `not json`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("invalid character 'o' in literal null (expecting 'u')", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("invalid character 'o' in literal null (expecting 'u')", "")}, SendPrep: setSendURL, }, { @@ -96,7 +96,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "message_id": 0 }`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid message id: 0", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Received invalid message id: 0", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/clickatell/clickatell.go b/handlers/clickatell/clickatell.go index 6e5ea76a7..d29e0741e 100644 --- a/handlers/clickatell/clickatell.go +++ b/handlers/clickatell/clickatell.go @@ -203,7 +203,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // try to read out our message id, if we can't then this was a failure externalID, err := jsonparser.GetString(respBody, "messages", "[0]", "apiMessageId") if err != nil { - clog.Error(err) + clog.RawError(err) } else { status.SetStatus(courier.MsgWired) status.SetExternalID(externalID) diff --git a/handlers/clickatell/clickatell_test.go b/handlers/clickatell/clickatell_test.go index c9f650ed9..4efb3d8b6 100644 --- a/handlers/clickatell/clickatell_test.go +++ b/handlers/clickatell/clickatell_test.go @@ -71,7 +71,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"content": "Error Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Key path not found", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Key path not found", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/clickmobile/clickmobile.go b/handlers/clickmobile/clickmobile.go index d59e2bf05..ce407c821 100644 --- a/handlers/clickmobile/clickmobile.go +++ b/handlers/clickmobile/clickmobile.go @@ -165,7 +165,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann if responseCode == "000" { status.SetStatus(courier.MsgWired) } else { - clog.Error(fmt.Errorf("Received invalid response content: %s", string(respBody))) + clog.RawError(fmt.Errorf("Received invalid response content: %s", string(respBody))) } } return status, nil diff --git a/handlers/clicksend/clicksend.go b/handlers/clicksend/clicksend.go index 4734d17ea..a5f241a6d 100644 --- a/handlers/clicksend/clicksend.go +++ b/handlers/clicksend/clicksend.go @@ -102,14 +102,14 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // first read our status s, err := jsonparser.GetString(respBody, "data", "messages", "[0]", "status") if s != "SUCCESS" { - clog.Error(errors.Errorf("received non SUCCESS status: %s", s)) + clog.RawError(errors.Errorf("received non SUCCESS status: %s", s)) return status, nil } // then get our external id id, err := jsonparser.GetString(respBody, "data", "messages", "[0]", "message_id") if err != nil { - clog.Error(errors.Errorf("unable to get message_id for message")) + clog.RawError(errors.Errorf("unable to get message_id for message")) return status, nil } diff --git a/handlers/clicksend/clicksend_test.go b/handlers/clicksend/clicksend_test.go index 29743a0b3..b5ac8e8f7 100644 --- a/handlers/clicksend/clicksend_test.go +++ b/handlers/clicksend/clicksend_test.go @@ -162,7 +162,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: failureResponse, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received non SUCCESS status: FAILURE", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received non SUCCESS status: FAILURE", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/dart/dart.go b/handlers/dart/dart.go index 5c4f9358b..29a84818e 100644 --- a/handlers/dart/dart.go +++ b/handlers/dart/dart.go @@ -14,6 +14,7 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/stringsx" "github.com/nyaruka/gocommon/urns" ) @@ -184,16 +185,16 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } - responseText := string(respBody) - if responseText != "000" { - errorMessage := "Unknown error" - if responseText == "001" { - errorMessage = "Error 001: Authentication Error" + responseCode := stringsx.Truncate(string(respBody), 3) + if responseCode != "000" { + errorMessage := "Unknown error." + if responseCode == "001" { + errorMessage = "Authentication error." + } else if responseCode == "101" { + errorMessage = "Account expired or invalid parameters." } - if responseText == "101" { - errorMessage = "Error 101: Account expired or invalid parameters" - } - clog.Error(fmt.Errorf(errorMessage)) + + clog.Error(courier.ErrorServiceSpecific("dart", responseCode, errorMessage)) return status, nil } diff --git a/handlers/dart/dart_test.go b/handlers/dart/dart_test.go index 8aabf2d9a..70cf9d2c0 100644 --- a/handlers/dart/dart_test.go +++ b/handlers/dart/dart_test.go @@ -147,7 +147,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Error 001: Authentication Error", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Error 001: Authentication Error", "")}, SendPrep: setSendURL, }, { @@ -158,7 +158,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Error 101: Account expired or invalid parameters", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Error 101: Account expired or invalid parameters", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/dmark/dmark.go b/handlers/dmark/dmark.go index 092bd20e9..70b75cfaf 100644 --- a/handlers/dmark/dmark.go +++ b/handlers/dmark/dmark.go @@ -143,7 +143,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // grab the external id externalID, err := jsonparser.GetString(respBody, "sms_id") if err != nil { - clog.Error(errors.Errorf("unable to get sms_id from body")) + clog.RawError(errors.Errorf("unable to get sms_id from body")) return status, nil } diff --git a/handlers/dmark/dmark_test.go b/handlers/dmark/dmark_test.go index 801cf6eb9..e1dd92d03 100644 --- a/handlers/dmark/dmark_test.go +++ b/handlers/dmark/dmark_test.go @@ -117,7 +117,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedHeaders: map[string]string{"Authorization": "Token Authy"}, ExpectedPostParams: map[string]string{"text": "Error Message", "receiver": "250788383383", "sender": "2020"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sms_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sms_id from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/external/external.go b/handlers/external/external.go index e03c31491..1cc2fe24c 100644 --- a/handlers/external/external.go +++ b/handlers/external/external.go @@ -369,7 +369,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann if responseContent == "" || strings.Contains(string(respBody), responseContent) { status.SetStatus(courier.MsgWired) } else { - clog.Error(fmt.Errorf("Received invalid response content: %s", string(respBody))) + clog.RawError(fmt.Errorf("Received invalid response content: %s", string(respBody))) } } diff --git a/handlers/external/external_test.go b/handlers/external/external_test.go index 17cdb7f4b..3a27e875f 100644 --- a/handlers/external/external_test.go +++ b/handlers/external/external_test.go @@ -625,7 +625,7 @@ var xmlSendWithResponseContentTestCases = []ChannelSendTestCase{ ExpectedRequestBody: `+250788383383Error Message2020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid response content: 1", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Received invalid response content: 1", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/facebook/facebook.go b/handlers/facebook/facebook.go index b31742bca..09e0c4c75 100644 --- a/handlers/facebook/facebook.go +++ b/handlers/facebook/facebook.go @@ -570,7 +570,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann externalID, err := jsonparser.GetString(respBody, "message_id") if err != nil { - clog.Error(errors.Errorf("unable to get message_id from body")) + clog.RawError(errors.Errorf("unable to get message_id from body")) return status, nil } @@ -580,7 +580,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann if msg.URN().IsFacebookRef() { recipientID, err := jsonparser.GetString(respBody, "recipient_id") if err != nil { - clog.Error(errors.Errorf("unable to get recipient_id from body")) + clog.RawError(errors.Errorf("unable to get recipient_id from body")) return status, nil } @@ -588,29 +588,29 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann realIDURN, err := urns.NewFacebookURN(recipientID) if err != nil { - clog.Error(errors.Errorf("unable to make facebook urn from %s", recipientID)) + clog.RawError(errors.Errorf("unable to make facebook urn from %s", recipientID)) } contact, err := h.Backend().GetContact(ctx, msg.Channel(), msg.URN(), "", "", clog) if err != nil { - clog.Error(errors.Errorf("unable to get contact for %s", msg.URN().String())) + clog.RawError(errors.Errorf("unable to get contact for %s", msg.URN().String())) } realURN, err := h.Backend().AddURNtoContact(ctx, msg.Channel(), contact, realIDURN) if err != nil { - clog.Error(errors.Errorf("unable to add real facebook URN %s to contact with uuid %s", realURN.String(), contact.UUID())) + clog.RawError(errors.Errorf("unable to add real facebook URN %s to contact with uuid %s", realURN.String(), contact.UUID())) } referralIDExtURN, err := urns.NewURNFromParts(urns.ExternalScheme, referralID, "", "") if err != nil { - clog.Error(errors.Errorf("unable to make ext urn from %s", referralID)) + clog.RawError(errors.Errorf("unable to make ext urn from %s", referralID)) } extURN, err := h.Backend().AddURNtoContact(ctx, msg.Channel(), contact, referralIDExtURN) if err != nil { - clog.Error(errors.Errorf("unable to add URN %s to contact with uuid %s", extURN.String(), contact.UUID())) + clog.RawError(errors.Errorf("unable to add URN %s to contact with uuid %s", extURN.String(), contact.UUID())) } referralFacebookURN, err := h.Backend().RemoveURNfromContact(ctx, msg.Channel(), contact, msg.URN()) if err != nil { - clog.Error(errors.Errorf("unable to remove referral facebook URN %s from contact with uuid %s", referralFacebookURN.String(), contact.UUID())) + clog.RawError(errors.Errorf("unable to remove referral facebook URN %s from contact with uuid %s", referralFacebookURN.String(), contact.UUID())) } } } diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index 580035f72..18339491c 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -843,7 +843,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index c920fd132..67af83a00 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -911,7 +911,7 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, externalID, err := jsonparser.GetString(respBody, "message_id") if err != nil { - clog.Error(errors.Errorf("unable to get message_id from body")) + clog.RawError(errors.Errorf("unable to get message_id from body")) return status, nil } @@ -921,7 +921,7 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, if msg.URN().IsFacebookRef() { recipientID, err := jsonparser.GetString(respBody, "recipient_id") if err != nil { - clog.Error(errors.Errorf("unable to get recipient_id from body")) + clog.RawError(errors.Errorf("unable to get recipient_id from body")) return status, nil } @@ -929,29 +929,29 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, realIDURN, err := urns.NewFacebookURN(recipientID) if err != nil { - clog.Error(errors.Errorf("unable to make facebook urn from %s", recipientID)) + clog.RawError(errors.Errorf("unable to make facebook urn from %s", recipientID)) } contact, err := h.Backend().GetContact(ctx, msg.Channel(), msg.URN(), "", "", clog) if err != nil { - clog.Error(errors.Errorf("unable to get contact for %s", msg.URN().String())) + clog.RawError(errors.Errorf("unable to get contact for %s", msg.URN().String())) } realURN, err := h.Backend().AddURNtoContact(ctx, msg.Channel(), contact, realIDURN) if err != nil { - clog.Error(errors.Errorf("unable to add real facebook URN %s to contact with uuid %s", realURN.String(), contact.UUID())) + clog.RawError(errors.Errorf("unable to add real facebook URN %s to contact with uuid %s", realURN.String(), contact.UUID())) } referralIDExtURN, err := urns.NewURNFromParts(urns.ExternalScheme, referralID, "", "") if err != nil { - clog.Error(errors.Errorf("unable to make ext urn from %s", referralID)) + clog.RawError(errors.Errorf("unable to make ext urn from %s", referralID)) } extURN, err := h.Backend().AddURNtoContact(ctx, msg.Channel(), contact, referralIDExtURN) if err != nil { - clog.Error(errors.Errorf("unable to add URN %s to contact with uuid %s", extURN.String(), contact.UUID())) + clog.RawError(errors.Errorf("unable to add URN %s to contact with uuid %s", extURN.String(), contact.UUID())) } referralFacebookURN, err := h.Backend().RemoveURNfromContact(ctx, msg.Channel(), contact, msg.URN()) if err != nil { - clog.Error(errors.Errorf("unable to remove referral facebook URN %s from contact with uuid %s", referralFacebookURN.String(), contact.UUID())) + clog.RawError(errors.Errorf("unable to remove referral facebook URN %s from contact with uuid %s", referralFacebookURN.String(), contact.UUID())) } } @@ -1299,7 +1299,7 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, respPayload := &wacMTResponse{} err = json.Unmarshal(respBody, respPayload) if err != nil { - clog.Error(errors.Errorf("unable to unmarshal response body")) + clog.RawError(errors.Errorf("unable to unmarshal response body")) return status, nil } externalID := respPayload.Messages[0].ID diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 14d972c8e..9836c5a28 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -1002,7 +1002,7 @@ var SendTestCasesFBA = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, SendPrep: setSendURL, }, { @@ -1115,7 +1115,7 @@ var SendTestCasesIG = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, SendPrep: setSendURL, }, { @@ -1243,7 +1243,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MsgText: "templated message", MsgURN: "whatsapp:250788123123", MsgMetadata: json.RawMessage(`{"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}}`), - ExpectedErrors: []courier.ChannelError{courier.NewChannelError(`unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError(`unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, "")}, }, { Label: "Interactive Button Message Send", diff --git a/handlers/firebase/firebase.go b/handlers/firebase/firebase.go index 322a5af1d..0efbccfcb 100644 --- a/handlers/firebase/firebase.go +++ b/handlers/firebase/firebase.go @@ -202,7 +202,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // was this successful success, _ := jsonparser.GetInt(respBody, "success") if success != 1 { - clog.Error(errors.Errorf("received non-1 value for success in response")) + clog.RawError(errors.Errorf("received non-1 value for success in response")) return status, nil } @@ -210,7 +210,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann if i == 0 { externalID, err := jsonparser.GetInt(respBody, "multicast_id") if err != nil { - clog.Error(errors.Errorf("unable to get multicast_id from response")) + clog.RawError(errors.Errorf("unable to get multicast_id from response")) return status, nil } status.SetExternalID(fmt.Sprintf("%d", externalID)) diff --git a/handlers/firebase/firebase_test.go b/handlers/firebase/firebase_test.go index 88b776f27..32245085b 100644 --- a/handlers/firebase/firebase_test.go +++ b/handlers/firebase/firebase_test.go @@ -165,7 +165,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "success": 0 }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received non-1 value for success in response", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received non-1 value for success in response", "")}, SendPrep: setSendURL, }, { @@ -176,7 +176,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "success": 1 }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get multicast_id from response", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get multicast_id from response", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/freshchat/freshchat.go b/handlers/freshchat/freshchat.go index 3cc009555..a8e1352d4 100644 --- a/handlers/freshchat/freshchat.go +++ b/handlers/freshchat/freshchat.go @@ -148,7 +148,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann msgimage.Image = &Image{URL: mediaURL} payload.Messages[0].MessageParts = append(payload.Messages[0].MessageParts, *msgimage) default: - clog.Error(fmt.Errorf("unknown media type: %s", mediaType)) + clog.Error(courier.ErrorUnsupportedMedia(mediaType)) } } diff --git a/handlers/i2sms/i2sms.go b/handlers/i2sms/i2sms.go index 0cb2ae3c1..e96a6ab68 100644 --- a/handlers/i2sms/i2sms.go +++ b/handlers/i2sms/i2sms.go @@ -126,7 +126,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann response := &mtResponse{} err = json.Unmarshal(respBody, response) if err != nil { - clog.Error(err) + clog.Error(courier.ErrorResponseUnparseable("JSON")) break } @@ -136,7 +136,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann status.SetExternalID(response.Result.SessionID) } else { status.SetStatus(courier.MsgFailed) - clog.Error(fmt.Errorf("Received invalid response code: %s", response.ErrorCode)) + clog.RawError(fmt.Errorf("Received invalid response code: %s", response.ErrorCode)) break } } diff --git a/handlers/i2sms/i2sms_test.go b/handlers/i2sms/i2sms_test.go index 9ffd8e2fd..53e217355 100644 --- a/handlers/i2sms/i2sms_test.go +++ b/handlers/i2sms/i2sms_test.go @@ -74,7 +74,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `not json`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("invalid character 'o' in literal null (expecting 'u')", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("invalid character 'o' in literal null (expecting 'u')", "")}, SendPrep: setSendURL, }, { @@ -84,7 +84,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"result":{}, "error_code": "10", "error_desc": "Failed"}`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid response code: 10", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Received invalid response code: 10", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/infobip/infobip.go b/handlers/infobip/infobip.go index a1bc04880..ae5150478 100644 --- a/handlers/infobip/infobip.go +++ b/handlers/infobip/infobip.go @@ -235,7 +235,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann groupID, err := jsonparser.GetInt(respBody, "messages", "[0]", "status", "groupId") if err != nil || (groupID != 1 && groupID != 3) { - clog.Error(errors.Errorf("received error status: '%d'", groupID)) + clog.RawError(errors.Errorf("received error status: '%d'", groupID)) return status, nil } diff --git a/handlers/infobip/infobip_test.go b/handlers/infobip/infobip_test.go index 425b318c8..879b28e3d 100644 --- a/handlers/infobip/infobip_test.go +++ b/handlers/infobip/infobip_test.go @@ -378,7 +378,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Simple Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error status: '2'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received error status: '2'", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 39dcf51c6..33322573a 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -192,7 +192,7 @@ func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) accessToken, err := jsonparser.GetString(respBody, "access_token") if err != nil { - clog.Error(errors.New("access_token not found in response")) + clog.RawError(errors.New("access_token not found in response")) clog.End() return h.Backend().WriteChannelLog(ctx, clog) } diff --git a/handlers/junebug/junebug.go b/handlers/junebug/junebug.go index dafa36b3c..6aced4c00 100644 --- a/handlers/junebug/junebug.go +++ b/handlers/junebug/junebug.go @@ -205,7 +205,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann externalID, err := jsonparser.GetString(respBody, "result", "message_id") if err != nil { - clog.Error(errors.Errorf("unable to get result.message_id from body")) + clog.RawError(errors.Errorf("unable to get result.message_id from body")) return status, nil } diff --git a/handlers/junebug/junebug_test.go b/handlers/junebug/junebug_test.go index dfaba63ef..346e78bca 100644 --- a/handlers/junebug/junebug_test.go +++ b/handlers/junebug/junebug_test.go @@ -179,7 +179,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, MockResponseBody: "not json", ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get result.message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get result.message_id from body", "")}, SendPrep: setSendURL, }, { @@ -189,7 +189,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, MockResponseBody: "{}", ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get result.message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get result.message_id from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/kaleyra/kaleyra.go b/handlers/kaleyra/kaleyra.go index e3e9b0f1b..e9fcd8d57 100644 --- a/handlers/kaleyra/kaleyra.go +++ b/handlers/kaleyra/kaleyra.go @@ -174,7 +174,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann part, err := writer.CreateFormFile("media", fileName) _, err = io.Copy(part, bytes.NewReader(attBody)) if err != nil { - clog.Error(err) + clog.RawError(err) kwaErr = err break } @@ -187,14 +187,14 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann for k, v := range baseForm { part, err := writer.CreateFormField(k) if err != nil { - clog.Error(err) + clog.RawError(err) kwaErr = err break attachmentsLoop } _, err = part.Write([]byte(v)) if err != nil { - clog.Error(err) + clog.RawError(err) kwaErr = err break attachmentsLoop } diff --git a/handlers/macrokiosk/macrokiosk_test.go b/handlers/macrokiosk/macrokiosk_test.go index a532b7b46..fe2926a0f 100644 --- a/handlers/macrokiosk/macrokiosk_test.go +++ b/handlers/macrokiosk/macrokiosk_test.go @@ -110,7 +110,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedMsgStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to parse response body from Macrokiosk", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to parse response body from Macrokiosk", "")}, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", diff --git a/handlers/mblox/mblox_test.go b/handlers/mblox/mblox_test.go index faa724119..97d78f7fd 100644 --- a/handlers/mblox/mblox_test.go +++ b/handlers/mblox/mblox_test.go @@ -137,7 +137,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedMsgStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to parse response body from MBlox", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to parse response body from MBlox", "")}, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", diff --git a/handlers/messangi/messangi.go b/handlers/messangi/messangi.go index 94e064a5b..85139b482 100644 --- a/handlers/messangi/messangi.go +++ b/handlers/messangi/messangi.go @@ -105,7 +105,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann response := &mtResponse{} err = xml.Unmarshal(respBody, response) if err != nil { - clog.Error(err) + clog.RawError(err) break } @@ -114,7 +114,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann status.SetStatus(courier.MsgWired) } else { status.SetStatus(courier.MsgFailed) - clog.Error(fmt.Errorf("Received invalid response description: %s", response.Description)) + clog.RawError(fmt.Errorf("Received invalid response description: %s", response.Description)) break } } diff --git a/handlers/messangi/messangi_test.go b/handlers/messangi/messangi_test.go index 98b3bff30..bd34eada8 100644 --- a/handlers/messangi/messangi_test.go +++ b/handlers/messangi/messangi_test.go @@ -91,7 +91,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `sendMTERRORCompleted`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid response description: Completed", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Received invalid response description: Completed", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/mtarget/mtarget.go b/handlers/mtarget/mtarget.go index 3bdc12da0..db74394ef 100644 --- a/handlers/mtarget/mtarget.go +++ b/handlers/mtarget/mtarget.go @@ -202,7 +202,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann status.SetExternalID(externalID) } else { status.SetStatus(courier.MsgFailed) - clog.Error(fmt.Errorf("Error status code, failing permanently")) + clog.RawError(fmt.Errorf("Error status code, failing permanently")) break } } diff --git a/handlers/mtarget/mtarget_test.go b/handlers/mtarget/mtarget_test.go index 7ca841050..119c13beb 100644 --- a/handlers/mtarget/mtarget_test.go +++ b/handlers/mtarget/mtarget_test.go @@ -118,7 +118,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"results":[{"code": "3", "ticket": "null"}]}`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Error status code, failing permanently", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Error status code, failing permanently", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/nexmo/nexmo.go b/handlers/nexmo/nexmo.go index 6573f2a13..cb70f30b9 100644 --- a/handlers/nexmo/nexmo.go +++ b/handlers/nexmo/nexmo.go @@ -179,7 +179,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann nexmoStatus, err := jsonparser.GetString(respBody, "messages", "[0]", "status") if err != nil || nexmoStatus != "0" { - clog.Error(errors.Errorf("failed to send message, received error status [%s]", nexmoStatus)) + clog.RawError(errors.Errorf("failed to send message, received error status [%s]", nexmoStatus)) return status, nil } diff --git a/handlers/nexmo/nexmo_test.go b/handlers/nexmo/nexmo_test.go index 66d2a9545..8fe2fb00e 100644 --- a/handlers/nexmo/nexmo_test.go +++ b/handlers/nexmo/nexmo_test.go @@ -169,7 +169,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Error status", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("failed to send message, received error status [10]", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("failed to send message, received error status [10]", "")}, SendPrep: setSendURL, }, { @@ -200,7 +200,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("failed to send message, received error status [1]", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("failed to send message, received error status [1]", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/novo/novo.go b/handlers/novo/novo.go index 3c1c5468f..2234a3f04 100644 --- a/handlers/novo/novo.go +++ b/handlers/novo/novo.go @@ -122,7 +122,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann status.SetStatus(courier.MsgWired) } else { status.SetStatus(courier.MsgFailed) - clog.Error(fmt.Errorf("received invalid response")) + clog.RawError(fmt.Errorf("received invalid response")) break } } diff --git a/handlers/novo/novo_test.go b/handlers/novo/novo_test.go index d93dba9f5..b420a313d 100644 --- a/handlers/novo/novo_test.go +++ b/handlers/novo/novo_test.go @@ -100,7 +100,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"error": "Incorrect Query String Authentication ","expectedQueryString": "8868;18686846480;test;"}`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received invalid response", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received invalid response", "")}, SendPrep: setSendURL, }, { @@ -110,7 +110,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"error": "Incorrect Query String Authentication ","expectedQueryString": "8868;18686846480;test;"}`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received invalid response", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received invalid response", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/plivo/plivo_test.go b/handlers/plivo/plivo_test.go index eaa940fa3..bdbc5ae28 100644 --- a/handlers/plivo/plivo_test.go +++ b/handlers/plivo/plivo_test.go @@ -105,7 +105,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedMsgStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to parse response body from Plivo", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to parse response body from Plivo", "")}, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index a390fedda..9b04926b2 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -159,14 +159,14 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann for _, attachment := range msg.Attachments() { fileAttachment, err := parseAttachmentToFileParams(msg, attachment, clog) if err != nil { - clog.Error(err) + clog.RawError(err) return status, nil } if fileAttachment != nil { err = sendFilePart(msg, botToken, fileAttachment, clog) if err != nil { - clog.Error(err) + clog.RawError(err) return status, nil } } @@ -175,7 +175,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann if msg.Text() != "" { err := sendTextMsgPart(msg, botToken, clog) if err != nil { - clog.Error(err) + clog.RawError(err) return status, nil } } diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index d0178558c..2c899e64a 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -206,7 +206,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{"channel":"U0123ABCDEF","text":"Hello"}`, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("invalid_auth", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("invalid_auth", "")}, SendPrep: setSendUrl, }, } diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index b22ee1247..63da3227a 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -312,7 +312,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann hasError = err != nil default: - clog.Error(fmt.Errorf("unknown attachment content type: %s", attachment.ContentType)) + clog.Error(courier.ErrorUnsupportedMedia(attachment.ContentType)) hasError = true } } diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index 19846a8cb..94f6b9ab4 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -846,7 +846,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "telegram:12345", MsgAttachments: []string{"unknown/foo:https://foo.bar/unknown.foo"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unknown attachment content type: unknown/foo", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unknown attachment content type: unknown/foo", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/telesom/telesom.go b/handlers/telesom/telesom.go index 2f54ad964..44fb2854f 100644 --- a/handlers/telesom/telesom.go +++ b/handlers/telesom/telesom.go @@ -122,7 +122,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann if strings.Contains(string(respBody), "Success") { status.SetStatus(courier.MsgWired) } else { - clog.Error(fmt.Errorf("Received invalid response content: %s", string(respBody))) + clog.RawError(fmt.Errorf("Received invalid response content: %s", string(respBody))) } } return status, nil diff --git a/handlers/test.go b/handlers/test.go index 4022f40bb..1ee2d56ff 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -276,7 +276,7 @@ type ChannelSendTestCase struct { ExpectedHeaders map[string]string ExpectedMsgStatus courier.MsgStatusValue ExpectedExternalID string - ExpectedErrors []courier.ChannelError + ExpectedErrors []*courier.ChannelError ExpectedStopEvent bool ExpectedContactURNs map[string]bool ExpectedNewURN string @@ -350,7 +350,7 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour // we don't currently distinguish between a returned error and logged errors if err != nil { - clog.Error(err) + clog.RawError(err) } assert.Equal(t, tc.ExpectedErrors, clog.Errors(), "unexpected errors logged") diff --git a/handlers/thinq/thinq.go b/handlers/thinq/thinq.go index 795ff19d0..96c9a150c 100644 --- a/handlers/thinq/thinq.go +++ b/handlers/thinq/thinq.go @@ -181,7 +181,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // try to get our external id externalID, err := jsonparser.GetString(respBody, "guid") if err != nil { - clog.Error(errors.New("Unable to read external ID")) + clog.RawError(errors.New("Unable to read external ID")) return status, nil } status.SetStatus(courier.MsgWired) @@ -214,7 +214,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // get our external id externalID, err := jsonparser.GetString(respBody, "guid") if err != nil { - clog.Error(errors.New("Unable to read external ID from guid field")) + clog.RawError(errors.New("Unable to read external ID from guid field")) return status, nil } diff --git a/handlers/thinq/thinq_test.go b/handlers/thinq/thinq_test.go index 153bce79a..50ed67838 100644 --- a/handlers/thinq/thinq_test.go +++ b/handlers/thinq/thinq_test.go @@ -139,7 +139,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"No External ID"}`, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Unable to read external ID from guid field", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Unable to read external ID from guid field", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index 4ee928087..b9c9c9d3d 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -299,7 +299,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, err } } - clog.Error(errors.Errorf("received error code from twilio '%d'", errorCode)) + clog.RawError(errors.Errorf("received error code from twilio '%d'", errorCode)) return status, nil } } @@ -307,7 +307,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // grab the external id externalID, err := jsonparser.GetString(respBody, "sid") if err != nil { - clog.Error(errors.Errorf("unable to get sid from body")) + clog.RawError(errors.Errorf("unable to get sid from body")) return status, nil } diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index 859b9d622..fc67d67bd 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -327,7 +327,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -338,7 +338,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -350,7 +350,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStopEvent: true, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, SendPrep: setSendURL, }, { @@ -361,7 +361,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -434,7 +434,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -445,7 +445,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -457,7 +457,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedStopEvent: true, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, SendPrep: setSendURL, }, { @@ -468,7 +468,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -519,7 +519,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -530,7 +530,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -542,7 +542,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "F", ExpectedStopEvent: true, - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, SendPrep: setSendURL, }, { @@ -553,7 +553,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -604,7 +604,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -615,7 +615,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -627,7 +627,7 @@ var swSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "F", ExpectedStopEvent: true, - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, SendPrep: setSendURL, }, { @@ -638,7 +638,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/twitter/twitter.go b/handlers/twitter/twitter.go index 7869750b0..b8953e801 100644 --- a/handlers/twitter/twitter.go +++ b/handlers/twitter/twitter.go @@ -297,10 +297,10 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann if strings.HasPrefix(mimeType, "image") || strings.HasPrefix(mimeType, "video") { mediaID, err = uploadMediaToTwitter(msg, mediaURL, mimeType, s3url, client, clog) if err != nil { - clog.Error(errors.Wrap(err, "unable to upload media to Twitter server")) + clog.RawError(errors.Wrap(err, "unable to upload media to Twitter server")) } } else { - clog.Error(errors.New("unable to upload media, unsupported Twitter attachment")) + clog.RawError(errors.New("unable to upload media, unsupported Twitter attachment")) } if mediaID != "" { @@ -345,7 +345,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann externalID, err := jsonparser.GetString(respBody, "event", "id") if err != nil { - clog.Error(errors.Errorf("unable to get message_id from body")) + clog.RawError(errors.Errorf("unable to get message_id from body")) return status, nil } diff --git a/handlers/twitter/twitter_test.go b/handlers/twitter/twitter_test.go index cb06ee4e3..89b6057bb 100644 --- a/handlers/twitter/twitter_test.go +++ b/handlers/twitter/twitter_test.go @@ -346,7 +346,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, ExpectedMsgStatus: "W", ExpectedExternalID: "133", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to upload media, unsupported Twitter attachment", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to upload media, unsupported Twitter attachment", "")}, SendPrep: setSendURL, }, { @@ -356,7 +356,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index 2de8ecade..5f33cbaa7 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -375,7 +375,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann msgText = "" default: - clog.Error(fmt.Errorf("unknown media type: %s", mediaType)) + clog.Error(courier.ErrorUnsupportedMedia(mediaType)) } } else { @@ -417,11 +417,11 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } responseStatus, err := jsonparser.GetInt(respBody, "status") if err != nil { - clog.Error(errors.Errorf("received invalid JSON response")) + clog.RawError(errors.Errorf("received invalid JSON response")) return status, nil } if responseStatus != 0 { - clog.Error(errors.Errorf("received non-0 status: '%d'", responseStatus)) + clog.RawError(errors.Errorf("received non-0 status: '%d'", responseStatus)) return status, nil } diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index 61ae1be45..e5fefcf58 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -146,7 +146,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received non-0 status: '3'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received non-0 status: '3'", "")}, SendPrep: setSendURL, }, { @@ -158,7 +158,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received invalid JSON response", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received invalid JSON response", "")}, SendPrep: setSendURL, }, { @@ -177,7 +177,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ var invalidTokenSendTestCases = []ChannelSendTestCase{ { Label: "Invalid token", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("missing auth token in config", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("missing auth token in config", "")}, }, } diff --git a/handlers/vk/vk.go b/handlers/vk/vk.go index e6bb15c58..843cb941f 100644 --- a/handlers/vk/vk.go +++ b/handlers/vk/vk.go @@ -448,7 +448,7 @@ func buildTextAndAttachmentParams(msg courier.Msg, clog *courier.ChannelLog) (st if attachment, err := handleMediaUploadAndGetAttachment(msg.Channel(), mediaTypeImage, mediaExt, mediaURL, clog); err == nil { msgAttachments = append(msgAttachments, attachment) } else { - clog.Error(err) + clog.RawError(err) } default: diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index c762a2f3f..1972fbc06 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -119,7 +119,7 @@ func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) accessToken, err := jsonparser.GetString(respBody, "access_token") if err != nil { - clog.Error(errors.New("access_token not found in response")) + clog.RawError(errors.New("access_token not found in response")) clog.End() return h.Backend().WriteChannelLog(ctx, clog) } diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index 1a35f1680..5ce476d79 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -545,7 +545,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann err = status.SetUpdatedURN(msg.URN(), newURN) if err != nil { - clog.Error(err) + clog.RawError(err) } } status.SetStatus(courier.MsgWired) @@ -627,7 +627,7 @@ func buildPayloads(msg courier.Msg, h *handler, clog *courier.ChannelLog) ([]int payload.Video = mediaPayload payloads = append(payloads, payload) } else { - clog.Error(fmt.Errorf("unknown attachment mime type: %s", mimeType)) + clog.Error(courier.ErrorUnsupportedMedia(mimeType)) break } } diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index df90cc449..e783eea16 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -577,7 +577,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Label: "Template Invalid Language", MsgText: "templated message", MsgURN: "whatsapp:250788123123", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError(`unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError(`unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, "")}, MsgMetadata: json.RawMessage(`{"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}}`), }, { diff --git a/handlers/zenvia/zenvia.go b/handlers/zenvia/zenvia.go index c5c886a64..7d5ee679d 100644 --- a/handlers/zenvia/zenvia.go +++ b/handlers/zenvia/zenvia.go @@ -264,7 +264,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann externalID, err := jsonparser.GetString(respBody, "id") if err != nil { - clog.Error(errors.Errorf("unable to get id from body")) + clog.RawError(errors.Errorf("unable to get id from body")) return status, nil } diff --git a/handlers/zenvia/zenvia_test.go b/handlers/zenvia/zenvia_test.go index 85456c120..6f35c4ae5 100644 --- a/handlers/zenvia/zenvia_test.go +++ b/handlers/zenvia/zenvia_test.go @@ -283,7 +283,7 @@ var defaultWhatsappSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"No External ID"}]}`, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get id from body", "")}, SendPrep: setSendURL, }, { @@ -359,7 +359,7 @@ var defaultSMSSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"No External ID"}]}`, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get id from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/zenviaold/zenviaold.go b/handlers/zenviaold/zenviaold.go index 49c578644..f74fa9a65 100644 --- a/handlers/zenviaold/zenviaold.go +++ b/handlers/zenviaold/zenviaold.go @@ -205,7 +205,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann responseMsgStatus, _ := jsonparser.GetString(respBody, "sendSmsResponse", "statusCode") msgStatus, found := statusMapping[responseMsgStatus] if msgStatus == courier.MsgErrored || !found { - clog.Error(errors.Errorf("received non-success response: '%s'", responseMsgStatus)) + clog.RawError(errors.Errorf("received non-success response: '%s'", responseMsgStatus)) return status, nil } diff --git a/handlers/zenviaold/zenviaold_test.go b/handlers/zenviaold/zenviaold_test.go index 655b2c069..d58d42d78 100644 --- a/handlers/zenviaold/zenviaold_test.go +++ b/handlers/zenviaold/zenviaold_test.go @@ -199,7 +199,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"No External ID","callbackOption":"FINAL","id":"10","aggregateId":""}}`, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received non-success response: '05'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received non-success response: '05'", "")}, SendPrep: setSendURL}, { Label: "Error Sending", diff --git a/sender.go b/sender.go index db486346a..5430b2c7b 100644 --- a/sender.go +++ b/sender.go @@ -214,7 +214,7 @@ func (w *Sender) sendMessage(msg Msg) { if err != nil { log.WithError(err).WithField("elapsed", duration).Error("error sending message") - clog.Error(err) + clog.RawError(err) // possible for handlers to only return an error in which case we construct an error status if status == nil { From 34325380af8c40ab25531d388836c664b5cd60ef Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 22 Sep 2022 10:49:48 -0500 Subject: [PATCH 182/294] Use ChannelError as pointer --- channel_log.go | 8 +++--- handler_test.go | 2 +- handlers/arabiacell/arabiacell_test.go | 4 +-- handlers/blackmyna/blackmyna_test.go | 2 +- handlers/burstsms/burstsms_test.go | 4 +-- handlers/clickatell/clickatell_test.go | 2 +- handlers/clicksend/clicksend_test.go | 2 +- handlers/dart/dart_test.go | 4 +-- handlers/dmark/dmark_test.go | 2 +- handlers/external/external_test.go | 2 +- handlers/facebook/facebook_test.go | 2 +- handlers/facebookapp/facebookapp_test.go | 6 ++--- handlers/firebase/firebase_test.go | 4 +-- handlers/i2sms/i2sms_test.go | 4 +-- handlers/infobip/infobip_test.go | 2 +- handlers/junebug/junebug_test.go | 4 +-- handlers/macrokiosk/macrokiosk_test.go | 2 +- handlers/mblox/mblox_test.go | 2 +- handlers/messangi/messangi_test.go | 2 +- handlers/mtarget/mtarget_test.go | 2 +- handlers/nexmo/nexmo_test.go | 4 +-- handlers/novo/novo_test.go | 4 +-- handlers/plivo/plivo_test.go | 2 +- handlers/slack/slack_test.go | 2 +- handlers/telegram/telegram_test.go | 2 +- handlers/test.go | 2 +- handlers/thinq/thinq_test.go | 2 +- handlers/twiml/twiml_test.go | 32 ++++++++++++------------ handlers/twitter/twitter_test.go | 4 +-- handlers/viber/viber_test.go | 6 ++--- handlers/whatsapp/whatsapp_test.go | 2 +- handlers/zenvia/zenvia_test.go | 4 +-- handlers/zenviaold/zenviaold_test.go | 2 +- 33 files changed, 65 insertions(+), 65 deletions(-) diff --git a/channel_log.go b/channel_log.go index 33ff124ba..d96dc829f 100644 --- a/channel_log.go +++ b/channel_log.go @@ -30,8 +30,8 @@ type ChannelError struct { code string } -func NewChannelError(message, code string) ChannelError { - return ChannelError{message: message, code: code} +func NewChannelError(message, code string) *ChannelError { + return &ChannelError{message: message, code: code} } func (e *ChannelError) Message() string { @@ -49,7 +49,7 @@ type ChannelLog struct { channel Channel msgID MsgID httpLogs []*httpx.Log - errors []ChannelError + errors []*ChannelError createdOn time.Time elapsed time.Duration @@ -132,7 +132,7 @@ func (l *ChannelLog) HTTPLogs() []*httpx.Log { return l.httpLogs } -func (l *ChannelLog) Errors() []ChannelError { +func (l *ChannelLog) Errors() []*ChannelError { return l.errors } diff --git a/handler_test.go b/handler_test.go index 95dfa48a2..1bbeb65da 100644 --- a/handler_test.go +++ b/handler_test.go @@ -154,7 +154,7 @@ func TestHandling(t *testing.T) { assert.Len(mb.WrittenChannelLogs(), 1) clog := mb.WrittenChannelLogs()[0] - assert.Equal([]courier.ChannelError{courier.NewChannelError("contains ********** seeds", "")}, clog.Errors()) + assert.Equal([]*courier.ChannelError{courier.NewChannelError("contains ********** seeds", "")}, clog.Errors()) assert.Len(clog.HTTPLogs(), 1) diff --git a/handlers/arabiacell/arabiacell_test.go b/handlers/arabiacell/arabiacell_test.go index 788095c0b..229cc6992 100644 --- a/handlers/arabiacell/arabiacell_test.go +++ b/handlers/arabiacell/arabiacell_test.go @@ -80,7 +80,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `not xml`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("EOF", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("EOF", "")}, SendPrep: setSendURL, }, { @@ -90,7 +90,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `501failure`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid response code: 501", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Received invalid response code: 501", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/blackmyna/blackmyna_test.go b/handlers/blackmyna/blackmyna_test.go index 5730f74d0..8881fc404 100644 --- a/handlers/blackmyna/blackmyna_test.go +++ b/handlers/blackmyna/blackmyna_test.go @@ -122,7 +122,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 200, - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("no external id returned in body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("no external id returned in body", "")}, ExpectedPostParams: map[string]string{"message": `No External ID`, "address": "+250788383383", "senderaddress": "2020"}, ExpectedMsgStatus: "E", SendPrep: setSendURL, diff --git a/handlers/burstsms/burstsms_test.go b/handlers/burstsms/burstsms_test.go index e41a887a6..948b997dc 100644 --- a/handlers/burstsms/burstsms_test.go +++ b/handlers/burstsms/burstsms_test.go @@ -86,7 +86,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `not json`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("invalid character 'o' in literal null (expecting 'u')", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("invalid character 'o' in literal null (expecting 'u')", "")}, SendPrep: setSendURL, }, { @@ -96,7 +96,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "message_id": 0 }`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid message id: 0", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Received invalid message id: 0", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/clickatell/clickatell_test.go b/handlers/clickatell/clickatell_test.go index c9f650ed9..4efb3d8b6 100644 --- a/handlers/clickatell/clickatell_test.go +++ b/handlers/clickatell/clickatell_test.go @@ -71,7 +71,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"content": "Error Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Key path not found", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Key path not found", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/clicksend/clicksend_test.go b/handlers/clicksend/clicksend_test.go index 29743a0b3..b5ac8e8f7 100644 --- a/handlers/clicksend/clicksend_test.go +++ b/handlers/clicksend/clicksend_test.go @@ -162,7 +162,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: failureResponse, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received non SUCCESS status: FAILURE", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received non SUCCESS status: FAILURE", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/dart/dart_test.go b/handlers/dart/dart_test.go index 8aabf2d9a..70cf9d2c0 100644 --- a/handlers/dart/dart_test.go +++ b/handlers/dart/dart_test.go @@ -147,7 +147,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Error 001: Authentication Error", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Error 001: Authentication Error", "")}, SendPrep: setSendURL, }, { @@ -158,7 +158,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Error 101: Account expired or invalid parameters", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Error 101: Account expired or invalid parameters", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/dmark/dmark_test.go b/handlers/dmark/dmark_test.go index 801cf6eb9..e1dd92d03 100644 --- a/handlers/dmark/dmark_test.go +++ b/handlers/dmark/dmark_test.go @@ -117,7 +117,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedHeaders: map[string]string{"Authorization": "Token Authy"}, ExpectedPostParams: map[string]string{"text": "Error Message", "receiver": "250788383383", "sender": "2020"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sms_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sms_id from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/external/external_test.go b/handlers/external/external_test.go index 17cdb7f4b..3a27e875f 100644 --- a/handlers/external/external_test.go +++ b/handlers/external/external_test.go @@ -625,7 +625,7 @@ var xmlSendWithResponseContentTestCases = []ChannelSendTestCase{ ExpectedRequestBody: `+250788383383Error Message2020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid response content: 1", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Received invalid response content: 1", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index 580035f72..18339491c 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -843,7 +843,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 14d972c8e..9836c5a28 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -1002,7 +1002,7 @@ var SendTestCasesFBA = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, SendPrep: setSendURL, }, { @@ -1115,7 +1115,7 @@ var SendTestCasesIG = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, SendPrep: setSendURL, }, { @@ -1243,7 +1243,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MsgText: "templated message", MsgURN: "whatsapp:250788123123", MsgMetadata: json.RawMessage(`{"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}}`), - ExpectedErrors: []courier.ChannelError{courier.NewChannelError(`unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError(`unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, "")}, }, { Label: "Interactive Button Message Send", diff --git a/handlers/firebase/firebase_test.go b/handlers/firebase/firebase_test.go index 88b776f27..32245085b 100644 --- a/handlers/firebase/firebase_test.go +++ b/handlers/firebase/firebase_test.go @@ -165,7 +165,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "success": 0 }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received non-1 value for success in response", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received non-1 value for success in response", "")}, SendPrep: setSendURL, }, { @@ -176,7 +176,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "success": 1 }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get multicast_id from response", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get multicast_id from response", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/i2sms/i2sms_test.go b/handlers/i2sms/i2sms_test.go index 9ffd8e2fd..53e217355 100644 --- a/handlers/i2sms/i2sms_test.go +++ b/handlers/i2sms/i2sms_test.go @@ -74,7 +74,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `not json`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("invalid character 'o' in literal null (expecting 'u')", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("invalid character 'o' in literal null (expecting 'u')", "")}, SendPrep: setSendURL, }, { @@ -84,7 +84,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"result":{}, "error_code": "10", "error_desc": "Failed"}`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid response code: 10", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Received invalid response code: 10", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/infobip/infobip_test.go b/handlers/infobip/infobip_test.go index 425b318c8..879b28e3d 100644 --- a/handlers/infobip/infobip_test.go +++ b/handlers/infobip/infobip_test.go @@ -378,7 +378,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Simple Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error status: '2'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received error status: '2'", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/junebug/junebug_test.go b/handlers/junebug/junebug_test.go index dfaba63ef..346e78bca 100644 --- a/handlers/junebug/junebug_test.go +++ b/handlers/junebug/junebug_test.go @@ -179,7 +179,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, MockResponseBody: "not json", ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get result.message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get result.message_id from body", "")}, SendPrep: setSendURL, }, { @@ -189,7 +189,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, MockResponseBody: "{}", ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get result.message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get result.message_id from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/macrokiosk/macrokiosk_test.go b/handlers/macrokiosk/macrokiosk_test.go index a532b7b46..fe2926a0f 100644 --- a/handlers/macrokiosk/macrokiosk_test.go +++ b/handlers/macrokiosk/macrokiosk_test.go @@ -110,7 +110,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedMsgStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to parse response body from Macrokiosk", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to parse response body from Macrokiosk", "")}, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", diff --git a/handlers/mblox/mblox_test.go b/handlers/mblox/mblox_test.go index faa724119..97d78f7fd 100644 --- a/handlers/mblox/mblox_test.go +++ b/handlers/mblox/mblox_test.go @@ -137,7 +137,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedMsgStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to parse response body from MBlox", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to parse response body from MBlox", "")}, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", diff --git a/handlers/messangi/messangi_test.go b/handlers/messangi/messangi_test.go index 98b3bff30..bd34eada8 100644 --- a/handlers/messangi/messangi_test.go +++ b/handlers/messangi/messangi_test.go @@ -91,7 +91,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `sendMTERRORCompleted`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Received invalid response description: Completed", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Received invalid response description: Completed", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/mtarget/mtarget_test.go b/handlers/mtarget/mtarget_test.go index 7ca841050..119c13beb 100644 --- a/handlers/mtarget/mtarget_test.go +++ b/handlers/mtarget/mtarget_test.go @@ -118,7 +118,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"results":[{"code": "3", "ticket": "null"}]}`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Error status code, failing permanently", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Error status code, failing permanently", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/nexmo/nexmo_test.go b/handlers/nexmo/nexmo_test.go index 66d2a9545..8fe2fb00e 100644 --- a/handlers/nexmo/nexmo_test.go +++ b/handlers/nexmo/nexmo_test.go @@ -169,7 +169,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Error status", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("failed to send message, received error status [10]", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("failed to send message, received error status [10]", "")}, SendPrep: setSendURL, }, { @@ -200,7 +200,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("failed to send message, received error status [1]", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("failed to send message, received error status [1]", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/novo/novo_test.go b/handlers/novo/novo_test.go index d93dba9f5..b420a313d 100644 --- a/handlers/novo/novo_test.go +++ b/handlers/novo/novo_test.go @@ -100,7 +100,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"error": "Incorrect Query String Authentication ","expectedQueryString": "8868;18686846480;test;"}`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received invalid response", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received invalid response", "")}, SendPrep: setSendURL, }, { @@ -110,7 +110,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"error": "Incorrect Query String Authentication ","expectedQueryString": "8868;18686846480;test;"}`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received invalid response", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received invalid response", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/plivo/plivo_test.go b/handlers/plivo/plivo_test.go index eaa940fa3..bdbc5ae28 100644 --- a/handlers/plivo/plivo_test.go +++ b/handlers/plivo/plivo_test.go @@ -105,7 +105,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedMsgStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to parse response body from Plivo", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to parse response body from Plivo", "")}, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index d0178558c..2c899e64a 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -206,7 +206,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{"channel":"U0123ABCDEF","text":"Hello"}`, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("invalid_auth", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("invalid_auth", "")}, SendPrep: setSendUrl, }, } diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index 19846a8cb..94f6b9ab4 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -846,7 +846,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "telegram:12345", MsgAttachments: []string{"unknown/foo:https://foo.bar/unknown.foo"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unknown attachment content type: unknown/foo", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unknown attachment content type: unknown/foo", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/test.go b/handlers/test.go index 4022f40bb..d3d4c7355 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -276,7 +276,7 @@ type ChannelSendTestCase struct { ExpectedHeaders map[string]string ExpectedMsgStatus courier.MsgStatusValue ExpectedExternalID string - ExpectedErrors []courier.ChannelError + ExpectedErrors []*courier.ChannelError ExpectedStopEvent bool ExpectedContactURNs map[string]bool ExpectedNewURN string diff --git a/handlers/thinq/thinq_test.go b/handlers/thinq/thinq_test.go index 153bce79a..50ed67838 100644 --- a/handlers/thinq/thinq_test.go +++ b/handlers/thinq/thinq_test.go @@ -139,7 +139,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"No External ID"}`, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("Unable to read external ID from guid field", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Unable to read external ID from guid field", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index 859b9d622..fc67d67bd 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -327,7 +327,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -338,7 +338,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -350,7 +350,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStopEvent: true, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, SendPrep: setSendURL, }, { @@ -361,7 +361,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -434,7 +434,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -445,7 +445,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -457,7 +457,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedStopEvent: true, ExpectedMsgStatus: "F", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, SendPrep: setSendURL, }, { @@ -468,7 +468,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -519,7 +519,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -530,7 +530,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -542,7 +542,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "F", ExpectedStopEvent: true, - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, SendPrep: setSendURL, }, { @@ -553,7 +553,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -604,7 +604,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -615,7 +615,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { @@ -627,7 +627,7 @@ var swSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "F", ExpectedStopEvent: true, - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, SendPrep: setSendURL, }, { @@ -638,7 +638,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/twitter/twitter_test.go b/handlers/twitter/twitter_test.go index cb06ee4e3..89b6057bb 100644 --- a/handlers/twitter/twitter_test.go +++ b/handlers/twitter/twitter_test.go @@ -346,7 +346,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, ExpectedMsgStatus: "W", ExpectedExternalID: "133", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to upload media, unsupported Twitter attachment", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to upload media, unsupported Twitter attachment", "")}, SendPrep: setSendURL, }, { @@ -356,7 +356,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index 61ae1be45..e5fefcf58 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -146,7 +146,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received non-0 status: '3'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received non-0 status: '3'", "")}, SendPrep: setSendURL, }, { @@ -158,7 +158,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received invalid JSON response", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received invalid JSON response", "")}, SendPrep: setSendURL, }, { @@ -177,7 +177,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ var invalidTokenSendTestCases = []ChannelSendTestCase{ { Label: "Invalid token", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("missing auth token in config", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("missing auth token in config", "")}, }, } diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index df90cc449..e783eea16 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -577,7 +577,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Label: "Template Invalid Language", MsgText: "templated message", MsgURN: "whatsapp:250788123123", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError(`unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError(`unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, "")}, MsgMetadata: json.RawMessage(`{"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}}`), }, { diff --git a/handlers/zenvia/zenvia_test.go b/handlers/zenvia/zenvia_test.go index 85456c120..6f35c4ae5 100644 --- a/handlers/zenvia/zenvia_test.go +++ b/handlers/zenvia/zenvia_test.go @@ -283,7 +283,7 @@ var defaultWhatsappSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"No External ID"}]}`, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get id from body", "")}, SendPrep: setSendURL, }, { @@ -359,7 +359,7 @@ var defaultSMSSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"No External ID"}]}`, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("unable to get id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get id from body", "")}, SendPrep: setSendURL, }, { diff --git a/handlers/zenviaold/zenviaold_test.go b/handlers/zenviaold/zenviaold_test.go index 655b2c069..d58d42d78 100644 --- a/handlers/zenviaold/zenviaold_test.go +++ b/handlers/zenviaold/zenviaold_test.go @@ -199,7 +199,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"No External ID","callbackOption":"FINAL","id":"10","aggregateId":""}}`, ExpectedMsgStatus: "E", - ExpectedErrors: []courier.ChannelError{courier.NewChannelError("received non-success response: '05'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received non-success response: '05'", "")}, SendPrep: setSendURL}, { Label: "Error Sending", From cd11d92ebc771bb2567ecf2d77b58dd378dfd084 Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Thu, 22 Sep 2022 08:57:51 -0700 Subject: [PATCH 183/294] Update cla.yml --- .github/workflows/cla.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 0fdd28f83..190a3fa1a 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -18,7 +18,7 @@ jobs: PERSONAL_ACCESS_TOKEN : ${{ secrets.CLA_TOKEN }} with: path-to-signatures: 'signatures/version1/cla.json' - path-to-document: 'https://github.com/nyaruka/legal/blob/main/TextIt%20CLA.md' + path-to-document: 'https://github.com/nyaruka/license/blob/main/TextIt_CLA.md' branch: 'main' allowlist: bot* remote-organization-name: 'nyaruka' From e89151ac757a8ab7eb69ea79b56dd0b254d1c254 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 22 Sep 2022 11:08:13 -0500 Subject: [PATCH 184/294] Update tests --- channel_log.go | 2 +- handlers/arabiacell/arabiacell_test.go | 4 ++-- handlers/burstsms/burstsms_test.go | 2 +- handlers/dart/dart.go | 14 ++++++-------- handlers/dart/dart_test.go | 4 ++-- handlers/i2sms/i2sms_test.go | 2 +- handlers/telegram/telegram_test.go | 4 ++-- 7 files changed, 15 insertions(+), 17 deletions(-) diff --git a/channel_log.go b/channel_log.go index 4c220ae03..fce5e351b 100644 --- a/channel_log.go +++ b/channel_log.go @@ -116,7 +116,7 @@ func (l *ChannelLog) HTTP(t *httpx.Trace) { } func (l *ChannelLog) Error(e *ChannelError) { - l.errors = append(l.errors, e) + l.errors = append(l.errors, e.Redact(l.redactor)) } func (l *ChannelLog) RawError(err error) { diff --git a/handlers/arabiacell/arabiacell_test.go b/handlers/arabiacell/arabiacell_test.go index 229cc6992..700ae9e41 100644 --- a/handlers/arabiacell/arabiacell_test.go +++ b/handlers/arabiacell/arabiacell_test.go @@ -80,7 +80,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `not xml`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("EOF", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseUnparseable("XML")}, SendPrep: setSendURL, }, { @@ -90,7 +90,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `501failure`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Received invalid response code: 501", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseStatusCode()}, SendPrep: setSendURL, }, { diff --git a/handlers/burstsms/burstsms_test.go b/handlers/burstsms/burstsms_test.go index 948b997dc..1c631879f 100644 --- a/handlers/burstsms/burstsms_test.go +++ b/handlers/burstsms/burstsms_test.go @@ -86,7 +86,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `not json`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("invalid character 'o' in literal null (expecting 'u')", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseUnparseable("XML")}, SendPrep: setSendURL, }, { diff --git a/handlers/dart/dart.go b/handlers/dart/dart.go index 29a84818e..5945ae099 100644 --- a/handlers/dart/dart.go +++ b/handlers/dart/dart.go @@ -21,6 +21,11 @@ import ( var ( sendURL = "http://202.43.169.11/APIhttpU/receive2waysms.php" maxMsgLength = 160 + + errorCodes = map[string]string{ + "001": "Authentication error.", + "101": "Account expired or invalid parameters.", + } ) type handler struct { @@ -187,14 +192,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann responseCode := stringsx.Truncate(string(respBody), 3) if responseCode != "000" { - errorMessage := "Unknown error." - if responseCode == "001" { - errorMessage = "Authentication error." - } else if responseCode == "101" { - errorMessage = "Account expired or invalid parameters." - } - - clog.Error(courier.ErrorServiceSpecific("dart", responseCode, errorMessage)) + clog.Error(courier.ErrorServiceSpecific("dart", responseCode, errorCodes[responseCode])) return status, nil } diff --git a/handlers/dart/dart_test.go b/handlers/dart/dart_test.go index 70cf9d2c0..a62112043 100644 --- a/handlers/dart/dart_test.go +++ b/handlers/dart/dart_test.go @@ -147,7 +147,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Error 001: Authentication Error", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("dart", "001", "Authentication error.")}, SendPrep: setSendURL, }, { @@ -158,7 +158,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Error 101: Account expired or invalid parameters", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("dart", "101", "Account expired or invalid parameters.")}, SendPrep: setSendURL, }, } diff --git a/handlers/i2sms/i2sms_test.go b/handlers/i2sms/i2sms_test.go index 53e217355..ca5d6538a 100644 --- a/handlers/i2sms/i2sms_test.go +++ b/handlers/i2sms/i2sms_test.go @@ -74,7 +74,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `not json`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("invalid character 'o' in literal null (expecting 'u')", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseUnparseable("JSON")}, SendPrep: setSendURL, }, { diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index 94f6b9ab4..d566557a7 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -841,12 +841,12 @@ var defaultSendTestCases = []ChannelSendTestCase{ SendPrep: setSendURL, }, { - Label: "Unknown Attachment", + Label: "Unknown attachment type", MsgText: "My pic!", MsgURN: "telegram:12345", MsgAttachments: []string{"unknown/foo:https://foo.bar/unknown.foo"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unknown attachment content type: unknown/foo", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorUnsupportedMedia("unknown/foo")}, SendPrep: setSendURL, }, } From 0f05d0ab2a5042856c147ac2fa1560a6589070fa Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 23 Sep 2022 10:54:57 -0500 Subject: [PATCH 185/294] Include requests to download attachments on the channel log for the incoming message --- backends/rapidpro/msg.go | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index fc7753741..dd0363caf 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -5,7 +5,6 @@ import ( "encoding/base64" "encoding/json" "fmt" - "io" "log" "mime" "net/http" @@ -22,6 +21,7 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/queue" "github.com/nyaruka/courier/utils" + "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/urns" "github.com/nyaruka/null" "github.com/pkg/errors" @@ -66,7 +66,7 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch var err error if strings.HasPrefix(attURL, "http://") || strings.HasPrefix(attURL, "https://") { - newURL, err = downloadAttachmentToStorage(ctx, b, channel, m.OrgID_, m.UUID_, attURL) + newURL, err = downloadAttachmentToStorage(ctx, b, channel, m.OrgID_, m.UUID_, attURL, clog) if err != nil { return err } @@ -242,7 +242,7 @@ WHERE // Attachment download and classification //----------------------------------------------------------------------------- -func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courier.Channel, orgID OrgID, msgUUID courier.MsgUUID, attURL string) (string, error) { +func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courier.Channel, orgID OrgID, msgUUID courier.MsgUUID, attURL string, clog *courier.ChannelLog) (string, error) { parsedURL, err := url.Parse(attURL) if err != nil { return "", err @@ -270,12 +270,10 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie } } - resp, err := utils.GetHTTPClient().Do(req) - if err != nil { - return "", err + trace, err := httpx.DoTrace(utils.GetHTTPClient(), req, nil, nil, 100*1024*1024) + if trace != nil { + clog.HTTP(trace) } - defer resp.Body.Close() - body, err := io.ReadAll(resp.Body) if err != nil { return "", err } @@ -287,7 +285,7 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie } // first try getting our mime type from the first 300 bytes of our body - fileType, _ := filetype.Match(body[:300]) + fileType, _ := filetype.Match(trace.ResponseBody[:300]) if fileType != filetype.Unknown { mimeType = fileType.MIME.Value extension = fileType.Extension @@ -302,7 +300,7 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie // we still don't know our mime type, use our content header instead if mimeType == "" { - mimeType, _, _ = mime.ParseMediaType(resp.Header.Get("Content-Type")) + mimeType, _, _ = mime.ParseMediaType(trace.Response.Header.Get("Content-Type")) if extension == "" { extensions, err := mime.ExtensionsByType(mimeType) if extensions == nil || err != nil { @@ -313,7 +311,7 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie } } - return saveAttachmentToStorage(ctx, b, orgID, msgUUID, mimeType, body, extension) + return saveAttachmentToStorage(ctx, b, orgID, msgUUID, mimeType, trace.ResponseBody, extension) } func saveAttachmentToStorage(ctx context.Context, b *backend, orgID OrgID, msgUUID courier.MsgUUID, contentType string, data []byte, extension string) (string, error) { From 22a85d7d1b4606fef3fcd07d36ddf2a3155583b8 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 23 Sep 2022 14:38:12 -0500 Subject: [PATCH 186/294] Convert more handler channel log error calls to use new error functions --- channel_log.go | 13 ++++++ channel_log_test.go | 56 +++++++++++++++++++++--- handlers/burstsms/burstsms.go | 2 +- handlers/burstsms/burstsms_test.go | 2 +- handlers/clickatell/clickatell.go | 2 +- handlers/clickatell/clickatell_test.go | 2 +- handlers/clickmobile/clickmobile.go | 4 +- handlers/clicksend/clicksend.go | 7 ++- handlers/clicksend/clicksend_test.go | 2 +- handlers/dmark/dmark.go | 3 +- handlers/dmark/dmark_test.go | 2 +- handlers/facebook/facebook.go | 4 +- handlers/facebook/facebook_test.go | 2 +- handlers/facebookapp/facebookapp.go | 4 +- handlers/facebookapp/facebookapp_test.go | 4 +- handlers/firebase/firebase.go | 5 +-- handlers/firebase/firebase_test.go | 4 +- handlers/infobip/infobip.go | 5 +-- handlers/infobip/infobip_test.go | 2 +- handlers/jiochat/jiochat.go | 2 +- handlers/junebug/junebug.go | 3 +- handlers/junebug/junebug_test.go | 4 +- handlers/thinq/thinq.go | 5 +-- handlers/thinq/thinq_test.go | 2 +- handlers/twiml/twiml.go | 2 +- handlers/twiml/twiml_test.go | 24 +++++----- handlers/viber/viber.go | 2 +- handlers/viber/viber_test.go | 2 +- handlers/wechat/wechat.go | 2 +- handlers/zenvia/zenvia.go | 4 +- handlers/zenvia/zenvia_test.go | 4 +- 31 files changed, 116 insertions(+), 65 deletions(-) diff --git a/channel_log.go b/channel_log.go index fce5e351b..83ba19436 100644 --- a/channel_log.go +++ b/channel_log.go @@ -2,6 +2,7 @@ package courier import ( "fmt" + "strings" "time" "github.com/nyaruka/gocommon/dates" @@ -43,6 +44,18 @@ func ErrorResponseUnparseable(format string) *ChannelError { return NewChannelError(fmt.Sprintf("Unable to parse response as %s.", format), "core:response_unparseable") } +func ErrorResponseValueMissing(key string) *ChannelError { + return NewChannelError(fmt.Sprintf("Unable to find '%s' response.", key), "core:response_value_missing") +} + +func ErrorResponseValueUnexpected(key string, expected ...string) *ChannelError { + es := make([]string, len(expected)) + for i := range expected { + es[i] = fmt.Sprintf("'%s'", expected[i]) + } + return NewChannelError(fmt.Sprintf("Expected '%s' in response to be %s.", key, strings.Join(es, " or ")), "core:response_value_unexpected") +} + func ErrorUnsupportedMedia(contentType string) *ChannelError { return NewChannelError(fmt.Sprintf("Unsupported attachment media type: %s.", contentType), "core:media_unsupported_type") } diff --git a/channel_log_test.go b/channel_log_test.go index 1b91aaf74..b3289bb3e 100644 --- a/channel_log_test.go +++ b/channel_log_test.go @@ -81,9 +81,55 @@ func TestChannelLog(t *testing.T) { } func TestChannelErrors(t *testing.T) { - assert.Equal(t, courier.NewChannelError("Unexpected response status code.", "core:response_status_code"), courier.ErrorResponseStatusCode()) - assert.Equal(t, courier.NewChannelError("Unable to parse response as FOO.", "core:response_unparseable"), courier.ErrorResponseUnparseable("FOO")) - assert.Equal(t, courier.NewChannelError("Unsupported attachment media type: image/tiff.", "core:media_unsupported_type"), courier.ErrorUnsupportedMedia("image/tiff")) - assert.Equal(t, courier.NewChannelError("Invalid FriendlyName.", "twilio:20002"), courier.ErrorServiceSpecific("twilio", "20002", "Invalid FriendlyName.")) - assert.Equal(t, courier.NewChannelError("Service specific error: 20003.", "twilio:20003"), courier.ErrorServiceSpecific("twilio", "20003", "")) + tcs := []struct { + err *courier.ChannelError + expectedMessage string + expectedCode string + }{ + { + courier.ErrorResponseStatusCode(), + "Unexpected response status code.", + "core:response_status_code", + }, + { + courier.ErrorResponseUnparseable("FOO"), + "Unable to parse response as FOO.", + "core:response_unparseable", + }, + { + courier.ErrorResponseValueMissing("id"), + "Unable to find 'id' response.", + "core:response_value_missing", + }, + { + courier.ErrorResponseValueUnexpected("status", "SUCCESS"), + "Expected 'status' in response to be 'SUCCESS'.", + "core:response_value_unexpected", + }, + { + courier.ErrorResponseValueUnexpected("status", "SUCCESS", "OK"), + "Expected 'status' in response to be 'SUCCESS' or 'OK'.", + "core:response_value_unexpected", + }, + { + courier.ErrorUnsupportedMedia("image/tiff"), + "Unsupported attachment media type: image/tiff.", + "core:media_unsupported_type", + }, + { + courier.ErrorServiceSpecific("twilio", "20002", "Invalid FriendlyName."), + "Invalid FriendlyName.", + "twilio:20002", + }, + { + courier.ErrorServiceSpecific("twilio", "20003", ""), + "Service specific error: 20003.", + "twilio:20003", + }, + } + + for _, tc := range tcs { + assert.Equal(t, tc.expectedMessage, tc.err.Message()) + assert.Equal(t, tc.expectedCode, tc.err.Code()) + } } diff --git a/handlers/burstsms/burstsms.go b/handlers/burstsms/burstsms.go index 0ab3e5fe5..4009850f1 100644 --- a/handlers/burstsms/burstsms.go +++ b/handlers/burstsms/burstsms.go @@ -102,7 +102,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann status.SetExternalID(fmt.Sprintf("%d", response.MessageID)) } else { status.SetStatus(courier.MsgFailed) - clog.RawError(fmt.Errorf("Received invalid message id: %d", response.MessageID)) + clog.Error(courier.ErrorResponseValueMissing("message_id")) break } } diff --git a/handlers/burstsms/burstsms_test.go b/handlers/burstsms/burstsms_test.go index 1c631879f..051515312 100644 --- a/handlers/burstsms/burstsms_test.go +++ b/handlers/burstsms/burstsms_test.go @@ -96,7 +96,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "message_id": 0 }`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Received invalid message id: 0", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("message_id")}, SendPrep: setSendURL, }, { diff --git a/handlers/clickatell/clickatell.go b/handlers/clickatell/clickatell.go index d29e0741e..ceae54e5a 100644 --- a/handlers/clickatell/clickatell.go +++ b/handlers/clickatell/clickatell.go @@ -203,7 +203,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // try to read out our message id, if we can't then this was a failure externalID, err := jsonparser.GetString(respBody, "messages", "[0]", "apiMessageId") if err != nil { - clog.RawError(err) + clog.Error(courier.ErrorResponseValueMissing("apiMessageId")) } else { status.SetStatus(courier.MsgWired) status.SetExternalID(externalID) diff --git a/handlers/clickatell/clickatell_test.go b/handlers/clickatell/clickatell_test.go index 4efb3d8b6..ac862d965 100644 --- a/handlers/clickatell/clickatell_test.go +++ b/handlers/clickatell/clickatell_test.go @@ -71,7 +71,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"content": "Error Message", "to": "250788383383", "from": "2020", "apiKey": "API-KEY"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Key path not found", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("apiMessageId")}, SendPrep: setSendURL, }, } diff --git a/handlers/clickmobile/clickmobile.go b/handlers/clickmobile/clickmobile.go index ce407c821..2125cfd77 100644 --- a/handlers/clickmobile/clickmobile.go +++ b/handlers/clickmobile/clickmobile.go @@ -161,11 +161,11 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } - responseCode, err := jsonparser.GetString(respBody, "code") + responseCode, _ := jsonparser.GetString(respBody, "code") if responseCode == "000" { status.SetStatus(courier.MsgWired) } else { - clog.RawError(fmt.Errorf("Received invalid response content: %s", string(respBody))) + clog.Error(courier.ErrorResponseValueUnexpected("code", "000")) } } return status, nil diff --git a/handlers/clicksend/clicksend.go b/handlers/clicksend/clicksend.go index a5f241a6d..ea885d3ab 100644 --- a/handlers/clicksend/clicksend.go +++ b/handlers/clicksend/clicksend.go @@ -11,7 +11,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/gocommon/httpx" - "github.com/pkg/errors" ) var ( @@ -100,16 +99,16 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } // first read our status - s, err := jsonparser.GetString(respBody, "data", "messages", "[0]", "status") + s, _ := jsonparser.GetString(respBody, "data", "messages", "[0]", "status") if s != "SUCCESS" { - clog.RawError(errors.Errorf("received non SUCCESS status: %s", s)) + clog.Error(courier.ErrorResponseValueUnexpected("status", "SUCCESS")) return status, nil } // then get our external id id, err := jsonparser.GetString(respBody, "data", "messages", "[0]", "message_id") if err != nil { - clog.RawError(errors.Errorf("unable to get message_id for message")) + clog.Error(courier.ErrorResponseValueMissing("message_id")) return status, nil } diff --git a/handlers/clicksend/clicksend_test.go b/handlers/clicksend/clicksend_test.go index b5ac8e8f7..1cfe9a75c 100644 --- a/handlers/clicksend/clicksend_test.go +++ b/handlers/clicksend/clicksend_test.go @@ -162,7 +162,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: failureResponse, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received non SUCCESS status: FAILURE", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueUnexpected("status", "SUCCESS")}, SendPrep: setSendURL, }, } diff --git a/handlers/dmark/dmark.go b/handlers/dmark/dmark.go index 70b75cfaf..b9a192950 100644 --- a/handlers/dmark/dmark.go +++ b/handlers/dmark/dmark.go @@ -11,7 +11,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/pkg/errors" ) var ( @@ -143,7 +142,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // grab the external id externalID, err := jsonparser.GetString(respBody, "sms_id") if err != nil { - clog.RawError(errors.Errorf("unable to get sms_id from body")) + clog.Error(courier.ErrorResponseValueMissing("sms_id")) return status, nil } diff --git a/handlers/dmark/dmark_test.go b/handlers/dmark/dmark_test.go index e1dd92d03..4ab893e66 100644 --- a/handlers/dmark/dmark_test.go +++ b/handlers/dmark/dmark_test.go @@ -117,7 +117,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedHeaders: map[string]string{"Authorization": "Token Authy"}, ExpectedPostParams: map[string]string{"text": "Error Message", "receiver": "250788383383", "sender": "2020"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sms_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("sms_id")}, SendPrep: setSendURL, }, { diff --git a/handlers/facebook/facebook.go b/handlers/facebook/facebook.go index 09e0c4c75..752436f49 100644 --- a/handlers/facebook/facebook.go +++ b/handlers/facebook/facebook.go @@ -570,7 +570,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann externalID, err := jsonparser.GetString(respBody, "message_id") if err != nil { - clog.RawError(errors.Errorf("unable to get message_id from body")) + clog.Error(courier.ErrorResponseValueMissing("message_id")) return status, nil } @@ -580,7 +580,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann if msg.URN().IsFacebookRef() { recipientID, err := jsonparser.GetString(respBody, "recipient_id") if err != nil { - clog.RawError(errors.Errorf("unable to get recipient_id from body")) + clog.Error(courier.ErrorResponseValueMissing("recipient_id")) return status, nil } diff --git a/handlers/facebook/facebook_test.go b/handlers/facebook/facebook_test.go index 18339491c..62e7b6195 100644 --- a/handlers/facebook/facebook_test.go +++ b/handlers/facebook/facebook_test.go @@ -843,7 +843,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("message_id")}, SendPrep: setSendURL, }, { diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 67af83a00..1932895a3 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -911,7 +911,7 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, externalID, err := jsonparser.GetString(respBody, "message_id") if err != nil { - clog.RawError(errors.Errorf("unable to get message_id from body")) + clog.Error(courier.ErrorResponseValueMissing("message_id")) return status, nil } @@ -921,7 +921,7 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, if msg.URN().IsFacebookRef() { recipientID, err := jsonparser.GetString(respBody, "recipient_id") if err != nil { - clog.RawError(errors.Errorf("unable to get recipient_id from body")) + clog.Error(courier.ErrorResponseValueMissing("recipient_id")) return status, nil } diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 9836c5a28..1990fa9db 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -1002,7 +1002,7 @@ var SendTestCasesFBA = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("message_id")}, SendPrep: setSendURL, }, { @@ -1115,7 +1115,7 @@ var SendTestCasesIG = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("message_id")}, SendPrep: setSendURL, }, { diff --git a/handlers/firebase/firebase.go b/handlers/firebase/firebase.go index 0efbccfcb..c19d17094 100644 --- a/handlers/firebase/firebase.go +++ b/handlers/firebase/firebase.go @@ -12,7 +12,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/gocommon/urns" - "github.com/pkg/errors" ) const ( @@ -202,7 +201,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // was this successful success, _ := jsonparser.GetInt(respBody, "success") if success != 1 { - clog.RawError(errors.Errorf("received non-1 value for success in response")) + clog.Error(courier.ErrorResponseValueUnexpected("success", "1")) return status, nil } @@ -210,7 +209,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann if i == 0 { externalID, err := jsonparser.GetInt(respBody, "multicast_id") if err != nil { - clog.RawError(errors.Errorf("unable to get multicast_id from response")) + clog.Error(courier.ErrorResponseValueMissing("multicast_id")) return status, nil } status.SetExternalID(fmt.Sprintf("%d", externalID)) diff --git a/handlers/firebase/firebase_test.go b/handlers/firebase/firebase_test.go index 32245085b..fe44a8fb2 100644 --- a/handlers/firebase/firebase_test.go +++ b/handlers/firebase/firebase_test.go @@ -165,7 +165,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "success": 0 }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received non-1 value for success in response", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueUnexpected("success", "1")}, SendPrep: setSendURL, }, { @@ -176,7 +176,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "success": 1 }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get multicast_id from response", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("multicast_id")}, SendPrep: setSendURL, }, { diff --git a/handlers/infobip/infobip.go b/handlers/infobip/infobip.go index ae5150478..2e53e10a8 100644 --- a/handlers/infobip/infobip.go +++ b/handlers/infobip/infobip.go @@ -13,7 +13,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/gocommon/httpx" - "github.com/pkg/errors" ) var sendURL = "https://api.infobip.com/sms/1/text/advanced" @@ -235,11 +234,11 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann groupID, err := jsonparser.GetInt(respBody, "messages", "[0]", "status", "groupId") if err != nil || (groupID != 1 && groupID != 3) { - clog.RawError(errors.Errorf("received error status: '%d'", groupID)) + clog.Error(courier.ErrorResponseValueUnexpected("groupId", "1", "3")) return status, nil } - externalID, err := jsonparser.GetString(respBody, "messages", "[0]", "messageId") + externalID, _ := jsonparser.GetString(respBody, "messages", "[0]", "messageId") if externalID != "" { status.SetExternalID(externalID) } diff --git a/handlers/infobip/infobip_test.go b/handlers/infobip/infobip_test.go index 879b28e3d..922c1ab1e 100644 --- a/handlers/infobip/infobip_test.go +++ b/handlers/infobip/infobip_test.go @@ -378,7 +378,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"messages":[{"from":"2020","destinations":[{"to":"250788383383","messageId":"10"}],"text":"Simple Message","notifyContentType":"application/json","intermediateReport":true,"notifyUrl":"https://localhost/c/ib/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/delivered"}]}`, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received error status: '2'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueUnexpected("groupId", "1", "3")}, SendPrep: setSendURL, }, } diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 33322573a..380fcc945 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -192,7 +192,7 @@ func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) accessToken, err := jsonparser.GetString(respBody, "access_token") if err != nil { - clog.RawError(errors.New("access_token not found in response")) + clog.Error(courier.ErrorResponseValueMissing("access_token")) clog.End() return h.Backend().WriteChannelLog(ctx, clog) } diff --git a/handlers/junebug/junebug.go b/handlers/junebug/junebug.go index 6aced4c00..ccfd9e94c 100644 --- a/handlers/junebug/junebug.go +++ b/handlers/junebug/junebug.go @@ -12,7 +12,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/gocommon/httpx" - "github.com/pkg/errors" ) var ( @@ -205,7 +204,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann externalID, err := jsonparser.GetString(respBody, "result", "message_id") if err != nil { - clog.RawError(errors.Errorf("unable to get result.message_id from body")) + clog.Error(courier.ErrorResponseValueMissing("message_id")) return status, nil } diff --git a/handlers/junebug/junebug_test.go b/handlers/junebug/junebug_test.go index 346e78bca..3f30e745a 100644 --- a/handlers/junebug/junebug_test.go +++ b/handlers/junebug/junebug_test.go @@ -179,7 +179,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, MockResponseBody: "not json", ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get result.message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("message_id")}, SendPrep: setSendURL, }, { @@ -189,7 +189,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, MockResponseBody: "{}", ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get result.message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("message_id")}, SendPrep: setSendURL, }, { diff --git a/handlers/thinq/thinq.go b/handlers/thinq/thinq.go index 96c9a150c..05dd94702 100644 --- a/handlers/thinq/thinq.go +++ b/handlers/thinq/thinq.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "encoding/json" - "errors" "fmt" "mime/multipart" "net/http" @@ -181,7 +180,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // try to get our external id externalID, err := jsonparser.GetString(respBody, "guid") if err != nil { - clog.RawError(errors.New("Unable to read external ID")) + clog.Error(courier.ErrorResponseValueMissing("guid")) return status, nil } status.SetStatus(courier.MsgWired) @@ -214,7 +213,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // get our external id externalID, err := jsonparser.GetString(respBody, "guid") if err != nil { - clog.RawError(errors.New("Unable to read external ID from guid field")) + clog.Error(courier.ErrorResponseValueMissing("guid")) return status, nil } diff --git a/handlers/thinq/thinq_test.go b/handlers/thinq/thinq_test.go index 50ed67838..2fdc9bad9 100644 --- a/handlers/thinq/thinq_test.go +++ b/handlers/thinq/thinq_test.go @@ -139,7 +139,7 @@ var sendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{"from_did":"2065551212","to_did":"2067791234","message":"No External ID"}`, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Unable to read external ID from guid field", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("guid")}, SendPrep: setSendURL, }, { diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index b9c9c9d3d..7b777f6c6 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -307,7 +307,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // grab the external id externalID, err := jsonparser.GetString(respBody, "sid") if err != nil { - clog.RawError(errors.Errorf("unable to get sid from body")) + clog.Error(courier.ErrorResponseValueMissing("sid")) return status, nil } diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index fc67d67bd..d5dfcc082 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -327,7 +327,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("sid")}, SendPrep: setSendURL, }, { @@ -338,7 +338,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("sid")}, SendPrep: setSendURL, }, { @@ -361,7 +361,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("sid")}, SendPrep: setSendURL, }, { @@ -434,7 +434,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("sid")}, SendPrep: setSendURL, }, { @@ -445,7 +445,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("sid")}, SendPrep: setSendURL, }, { @@ -468,7 +468,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("sid")}, SendPrep: setSendURL, }, { @@ -519,7 +519,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("sid")}, SendPrep: setSendURL, }, { @@ -530,7 +530,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("sid")}, SendPrep: setSendURL, }, { @@ -553,7 +553,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("sid")}, SendPrep: setSendURL, }, { @@ -604,7 +604,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 401, ExpectedPostParams: map[string]string{"Body": "Error Message", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("sid")}, SendPrep: setSendURL, }, { @@ -615,7 +615,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "Error Code", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("sid")}, SendPrep: setSendURL, }, { @@ -638,7 +638,7 @@ var swSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"Body": "No SID", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get sid from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("sid")}, SendPrep: setSendURL, }, { diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index 5f33cbaa7..0eb5c09c8 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -417,7 +417,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } responseStatus, err := jsonparser.GetInt(respBody, "status") if err != nil { - clog.RawError(errors.Errorf("received invalid JSON response")) + clog.Error(courier.ErrorResponseUnparseable("JSON")) return status, nil } if responseStatus != 0 { diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index e5fefcf58..2c214ceb5 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -158,7 +158,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received invalid JSON response", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseUnparseable("JSON")}, SendPrep: setSendURL, }, { diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index 1972fbc06..dbf44819f 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -119,7 +119,7 @@ func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) accessToken, err := jsonparser.GetString(respBody, "access_token") if err != nil { - clog.RawError(errors.New("access_token not found in response")) + clog.Error(courier.ErrorResponseValueMissing("access_token")) clog.End() return h.Backend().WriteChannelLog(ctx, clog) } diff --git a/handlers/zenvia/zenvia.go b/handlers/zenvia/zenvia.go index 7d5ee679d..fe9026ed3 100644 --- a/handlers/zenvia/zenvia.go +++ b/handlers/zenvia/zenvia.go @@ -13,7 +13,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/gocommon/urns" - "github.com/pkg/errors" ) var ( @@ -264,12 +263,11 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann externalID, err := jsonparser.GetString(respBody, "id") if err != nil { - clog.RawError(errors.Errorf("unable to get id from body")) + clog.Error(courier.ErrorResponseValueMissing("id")) return status, nil } status.SetExternalID(externalID) - // this was wired successfully status.SetStatus(courier.MsgWired) return status, nil } diff --git a/handlers/zenvia/zenvia_test.go b/handlers/zenvia/zenvia_test.go index 6f35c4ae5..d9eb3077e 100644 --- a/handlers/zenvia/zenvia_test.go +++ b/handlers/zenvia/zenvia_test.go @@ -283,7 +283,7 @@ var defaultWhatsappSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"No External ID"}]}`, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("id")}, SendPrep: setSendURL, }, { @@ -359,7 +359,7 @@ var defaultSMSSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"from":"2020","to":"250788383383","contents":[{"type":"text","text":"No External ID"}]}`, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("id")}, SendPrep: setSendURL, }, { From deab64fd23f5d145e8813c4c62a0dcfcdf341c49 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 23 Sep 2022 15:22:32 -0500 Subject: [PATCH 187/294] Some test cleanup --- .../highconnection/highconnection_test.go | 84 +++--- handlers/hormuud/hormuud_test.go | 9 +- handlers/jiochat/jiochat_test.go | 108 +++++-- handlers/junebug/junebug_test.go | 159 ++++++++--- handlers/kaleyra/kaleyra.go | 6 +- handlers/kaleyra/kaleyra_test.go | 95 ------- handlers/kannel/kannel_test.go | 267 +++++++++++++----- handlers/line/line_test.go | 146 +++++++--- handlers/utils.go | 8 + handlers/utils_test.go | 97 +++++++ 10 files changed, 667 insertions(+), 312 deletions(-) create mode 100644 handlers/utils_test.go diff --git a/handlers/highconnection/highconnection_test.go b/handlers/highconnection/highconnection_test.go index ec3a8103a..2be804227 100644 --- a/handlers/highconnection/highconnection_test.go +++ b/handlers/highconnection/highconnection_test.go @@ -90,11 +90,12 @@ func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", - MsgURN: "tel:+250788383383", - ExpectedMsgStatus: "W", - MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, + MockResponseStatus: 200, ExpectedURLParams: map[string]string{ "accountid": "Username", "password": "Password", @@ -106,12 +107,14 @@ var defaultSendTestCases = []ChannelSendTestCase{ "ret_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status", "ret_mo_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive", }, - MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Plain Send without flow", - MsgText: "Simple Message", - MsgURN: "tel:+250788383383", ExpectedMsgStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Plain Send without flow", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseStatus: 200, ExpectedURLParams: map[string]string{ "accountid": "Username", "password": "Password", @@ -123,13 +126,15 @@ var defaultSendTestCases = []ChannelSendTestCase{ "ret_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status", "ret_mo_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive", }, - MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: "☺", - MsgURN: "tel:+250788383383", ExpectedMsgStatus: "W", - MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "tel:+250788383383", + MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, + MockResponseStatus: 200, ExpectedURLParams: map[string]string{ "accountid": "Username", "password": "Password", @@ -141,13 +146,15 @@ var defaultSendTestCases = []ChannelSendTestCase{ "ret_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status", "ret_mo_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive", }, - MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Long Send", - MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - MsgURN: "tel:+250788383383", ExpectedMsgStatus: "W", - MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, + SendPrep: setSendURL, + }, + { + Label: "Long Send", + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, + MockResponseStatus: 200, ExpectedURLParams: map[string]string{ "accountid": "Username", "password": "Password", @@ -159,14 +166,16 @@ var defaultSendTestCases = []ChannelSendTestCase{ "ret_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status", "ret_mo_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive", }, - MockResponseStatus: 200, - SendPrep: setSendURL}, - {Label: "Send Attachement", - MsgText: "My pic!", - MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MsgURN: "tel:+250788383383", ExpectedMsgStatus: "W", - MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, + SendPrep: setSendURL, + }, + { + Label: "Send Attachement", + MsgText: "My pic!", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MsgURN: "tel:+250788383383", + MsgFlow: &courier.FlowReference{UUID: "9de3663f-c5c5-4c92-9f45-ecbc09abcc85", Name: "Favorites"}, + MockResponseStatus: 200, ExpectedURLParams: map[string]string{ "accountid": "Username", "password": "Password", @@ -178,14 +187,17 @@ var defaultSendTestCases = []ChannelSendTestCase{ "ret_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status", "ret_mo_url": "https://localhost/c/hx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive", }, - MockResponseStatus: 200, - SendPrep: setSendURL}, - - {Label: "Error Sending", - MsgText: "Error Sending", MsgURN: "tel:+250788383383", - ExpectedMsgStatus: "E", + ExpectedMsgStatus: "W", + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Sending", + MsgURN: "tel:+250788383383", MockResponseStatus: 403, - SendPrep: setSendURL}, + ExpectedMsgStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/hormuud/hormuud_test.go b/handlers/hormuud/hormuud_test.go index afd922a07..315f66406 100644 --- a/handlers/hormuud/hormuud_test.go +++ b/handlers/hormuud/hormuud_test.go @@ -121,10 +121,13 @@ var sendTestCases = []ChannelSendTestCase{ } var tokenTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", ExpectedMsgStatus: "E", - SendPrep: setSendURL}, + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index fc84108a3..ce2376c1a 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -16,7 +16,6 @@ import ( "time" "github.com/nyaruka/courier" - "github.com/nyaruka/courier/handlers" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/urns" @@ -102,7 +101,7 @@ func addValidSignature(r *http.Request) { nonce := "nonce" stringSlice := []string{"secret", timestamp, nonce} - sort.Sort(sort.StringSlice(stringSlice)) + sort.Strings(stringSlice) value := strings.Join(stringSlice, "") @@ -126,7 +125,7 @@ func addInvalidSignature(r *http.Request) { nonce := "nonce" stringSlice := []string{"secret", timestamp, nonce} - sort.Sort(sort.StringSlice(stringSlice)) + sort.Strings(stringSlice) value := strings.Join(stringSlice, "") @@ -144,29 +143,80 @@ func addInvalidSignature(r *http.Request) { } var testCases = []ChannelHandleTestCase{ - {Label: "Receive Message", URL: receiveURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedMsgText: Sp("Simple Message"), ExpectedURN: "jiochat:1234", ExpectedExternalID: "123456", - ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, - - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid jiochat id"}, - {Label: "Missing params", URL: receiveURL, Data: missingParamsRequired, ExpectedRespStatus: 400, ExpectedBodyContains: "Error:Field validation"}, - {Label: "Missing params Event or MsgId", URL: receiveURL, Data: missingParams, ExpectedRespStatus: 400, ExpectedBodyContains: "missing parameters, must have either 'MsgId' or 'Event'"}, - - {Label: "Receive Image", URL: receiveURL, Data: imageMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedMsgText: Sp(""), ExpectedURN: "jiochat:1234", ExpectedExternalID: "123456", - ExpectedAttachments: []string{"https://channels.jiochat.com/media/download.action?media_id=12"}, - ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC)}, - - {Label: "Subscribe Event", URL: receiveURL, Data: subscribeEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "Event Accepted", - ExpectedEvent: courier.NewConversation, ExpectedURN: "jiochat:1234"}, - - {Label: "Unsubscribe Event", URL: receiveURL, Data: unsubscribeEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "unknown event"}, - - {Label: "Verify URL", URL: verifyURL, ExpectedRespStatus: 200, ExpectedBodyContains: "SUCCESS", - PrepRequest: addValidSignature}, - - {Label: "Verify URL Invalid signature", URL: verifyURL, ExpectedRespStatus: 400, ExpectedBodyContains: "unknown request", - PrepRequest: addInvalidSignature}, + { + Label: "Receive Message", + URL: receiveURL, + Data: validMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Simple Message"), + ExpectedURN: "jiochat:1234", + ExpectedExternalID: "123456", + ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC), + }, + { + Label: "Invalid URN", + URL: receiveURL, + Data: invalidURN, + ExpectedRespStatus: 400, + ExpectedBodyContains: "invalid jiochat id", + }, + { + Label: "Missing params", + URL: receiveURL, + Data: missingParamsRequired, + ExpectedRespStatus: 400, + ExpectedBodyContains: "Error:Field validation", + }, + { + Label: "Missing params Event or MsgId", + URL: receiveURL, + Data: missingParams, + ExpectedRespStatus: 400, + ExpectedBodyContains: "missing parameters, must have either 'MsgId' or 'Event'", + }, + { + Label: "Receive Image", + URL: receiveURL, + Data: imageMessage, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedURN: "jiochat:1234", + ExpectedExternalID: "123456", + ExpectedAttachments: []string{"https://channels.jiochat.com/media/download.action?media_id=12"}, + ExpectedDate: time.Date(2018, 2, 16, 9, 47, 4, 438000000, time.UTC), + }, + { + Label: "Subscribe Event", + URL: receiveURL, + Data: subscribeEvent, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Event Accepted", + ExpectedEvent: courier.NewConversation, + ExpectedURN: "jiochat:1234", + }, + { + Label: "Unsubscribe Event", + URL: receiveURL, + Data: unsubscribeEvent, + ExpectedRespStatus: 200, + ExpectedBodyContains: "unknown event", + }, + { + Label: "Verify URL", + URL: verifyURL, + ExpectedRespStatus: 200, + ExpectedBodyContains: "SUCCESS", + PrepRequest: addValidSignature, + }, + { + Label: "Verify URL Invalid signature", + URL: verifyURL, + ExpectedRespStatus: 400, + ExpectedBodyContains: "unknown request", + PrepRequest: addInvalidSignature, + }, } func TestHandler(t *testing.T) { @@ -233,7 +283,7 @@ func buildMockJCAPI(testCases []ChannelHandleTestCase) *httptest.Server { defer r.Body.Close() if authorizationHeader != "Bearer ACCESS_TOKEN" { - http.Error(w, "invalid file", 403) + http.Error(w, "invalid file", http.StatusForbidden) return } @@ -283,7 +333,7 @@ func TestDescribeURN(t *testing.T) { conn.Close() s := newServer(mb) - handler := &handler{handlers.NewBaseHandler(courier.ChannelType("JC"), "Jiochat")} + handler := &handler{NewBaseHandler(courier.ChannelType("JC"), "Jiochat")} handler.Initialize(s) clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], handler.RedactValues(testChannels[0])) @@ -314,7 +364,7 @@ func TestBuildMediaRequest(t *testing.T) { conn.Close() s := newServer(mb) - handler := &handler{handlers.NewBaseHandler(courier.ChannelType("JC"), "Jiochat")} + handler := &handler{NewBaseHandler(courier.ChannelType("JC"), "Jiochat")} handler.Initialize(s) tcs := []struct { diff --git a/handlers/junebug/junebug_test.go b/handlers/junebug/junebug_test.go index 3f30e745a..6664ad2b4 100644 --- a/handlers/junebug/junebug_test.go +++ b/handlers/junebug/junebug_test.go @@ -94,44 +94,133 @@ var ( ) var testCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: inboundURL, Data: validMsg, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedMsgText: Sp("hello world"), ExpectedURN: "tel:+250788383383", - ExpectedDate: time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC)}, - - {Label: "Invalid URN", URL: inboundURL, Data: invalidURN, - ExpectedRespStatus: 400, ExpectedBodyContains: "phone number supplied is not a number"}, - {Label: "Invalid Timestamp", URL: inboundURL, Data: invalidTimestamp, - ExpectedRespStatus: 400, ExpectedBodyContains: "unable to parse date"}, - {Label: "Missing Message ID", URL: inboundURL, Data: missingMessageID, - ExpectedRespStatus: 400, ExpectedBodyContains: "'MessageID' failed on the 'required'"}, - - {Label: "Receive Pending Event", URL: eventURL, Data: pendingEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "Ignored"}, - {Label: "Receive Sent Event", URL: eventURL, Data: sentEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedExternalID: "xx12345", ExpectedMsgStatus: "S"}, - {Label: "Receive Delivered Event", URL: eventURL, Data: deliveredEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedExternalID: "xx12345", ExpectedMsgStatus: "D"}, - {Label: "Receive Failed Event", URL: eventURL, Data: failedEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedExternalID: "xx12345", ExpectedMsgStatus: "F"}, - {Label: "Receive Unknown Event", URL: eventURL, Data: unknownEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "Ignored"}, - - {Label: "Receive Invalid JSON", URL: eventURL, Data: "not json", ExpectedRespStatus: 400, ExpectedBodyContains: "Error"}, - {Label: "Receive Missing Event Type", URL: eventURL, Data: missingEventType, ExpectedRespStatus: 400, ExpectedBodyContains: "Error"}, + { + Label: "Receive Valid Message", + URL: inboundURL, + Data: validMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("hello world"), + ExpectedURN: "tel:+250788383383", + ExpectedDate: time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC), + }, + { + Label: "Invalid URN", + URL: inboundURL, + Data: invalidURN, + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", + }, + { + Label: "Invalid Timestamp", + URL: inboundURL, + Data: invalidTimestamp, + ExpectedRespStatus: 400, + ExpectedBodyContains: "unable to parse date", + }, + { + Label: "Missing Message ID", + URL: inboundURL, + Data: missingMessageID, + ExpectedRespStatus: 400, + ExpectedBodyContains: "'MessageID' failed on the 'required'", + }, + { + Label: "Receive Pending Event", + URL: eventURL, + Data: pendingEvent, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Ignored", + }, + { + Label: "Receive Sent Event", + URL: eventURL, + Data: sentEvent, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedExternalID: "xx12345", + ExpectedMsgStatus: "S", + }, + { + Label: "Receive Delivered Event", + URL: eventURL, + Data: deliveredEvent, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedExternalID: "xx12345", + ExpectedMsgStatus: "D", + }, + { + Label: "Receive Failed Event", + URL: eventURL, + Data: failedEvent, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedExternalID: "xx12345", + ExpectedMsgStatus: "F", + }, + { + Label: "Receive Unknown Event", + URL: eventURL, + Data: unknownEvent, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Ignored", + }, + { + Label: "Receive Invalid JSON", + URL: eventURL, + Data: "not json", + ExpectedRespStatus: 400, + ExpectedBodyContains: "Error", + }, + { + Label: "Receive Missing Event Type", + URL: eventURL, + Data: missingEventType, + ExpectedRespStatus: 400, + ExpectedBodyContains: "Error", + }, } var authenticatedTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: inboundURL, Data: validMsg, Headers: map[string]string{"Authorization": "Token sesame"}, - ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedMsgText: Sp("hello world"), ExpectedURN: "tel:+250788383383", - ExpectedDate: time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC)}, - - {Label: "Invalid Incoming Authorization", URL: inboundURL, Data: validMsg, Headers: map[string]string{"Authorization": "Token foo"}, - ExpectedRespStatus: 401, ExpectedBodyContains: "Unauthorized"}, - - {Label: "Receive Sent Event", URL: eventURL, Data: sentEvent, Headers: map[string]string{"Authorization": "Token sesame"}, - ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedExternalID: "xx12345", ExpectedMsgStatus: "S"}, - {Label: "Invalid Incoming Authorization", URL: eventURL, Data: sentEvent, Headers: map[string]string{"Authorization": "Token foo"}, - ExpectedRespStatus: 401, ExpectedBodyContains: "Unauthorized"}, + { + Label: "Receive Valid Message", + URL: inboundURL, + Data: validMsg, + Headers: map[string]string{"Authorization": "Token sesame"}, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("hello world"), + ExpectedURN: "tel:+250788383383", + ExpectedDate: time.Date(2017, 01, 01, 1, 2, 3, 50000000, time.UTC), + }, + { + Label: "Invalid Incoming Authorization", + URL: inboundURL, + Data: validMsg, + Headers: map[string]string{"Authorization": "Token foo"}, + ExpectedRespStatus: 401, + ExpectedBodyContains: "Unauthorized", + }, + + { + Label: "Receive Sent Event", + URL: eventURL, + Data: sentEvent, + Headers: map[string]string{"Authorization": "Token sesame"}, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedExternalID: "xx12345", + ExpectedMsgStatus: "S", + }, + { + Label: "Invalid Incoming Authorization", + URL: eventURL, + Data: sentEvent, + Headers: map[string]string{"Authorization": "Token foo"}, + ExpectedRespStatus: 401, + ExpectedBodyContains: "Unauthorized", + }, } func TestHandler(t *testing.T) { diff --git a/handlers/kaleyra/kaleyra.go b/handlers/kaleyra/kaleyra.go index e9fcd8d57..5c03df133 100644 --- a/handlers/kaleyra/kaleyra.go +++ b/handlers/kaleyra/kaleyra.go @@ -8,7 +8,6 @@ import ( "mime/multipart" "net/http" "net/url" - "regexp" "strconv" "strings" "time" @@ -26,8 +25,7 @@ const ( ) var ( - baseURL = "https://api.kaleyra.io" - urlRegex = regexp.MustCompile(`https?:\/\/(www\.)?[^\W][-a-zA-Z0-9@:%.\+~#=]{1,256}[^\W]\.[a-zA-Z()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)`) + baseURL = "https://api.kaleyra.io" ) func init() { @@ -212,7 +210,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann baseForm := h.newSendForm(msg.Channel(), "text", msg.URN().Path()) baseForm["body"] = msg.Text() // checks if the message has a valid url to activate the preview - if urlRegex.MatchString(msg.Text()) { + if handlers.IsURL(msg.Text()) { baseForm["preview_url"] = "true" } for k, v := range baseForm { diff --git a/handlers/kaleyra/kaleyra_test.go b/handlers/kaleyra/kaleyra_test.go index 6b4954b2f..2311284a5 100644 --- a/handlers/kaleyra/kaleyra_test.go +++ b/handlers/kaleyra/kaleyra_test.go @@ -241,98 +241,3 @@ func TestSending(t *testing.T) { RunChannelSendTestCases(t, testChannels[0], newHandler(), mockedSendTestCases, []string{"123456"}, nil) } - -var urlTestCases = []struct { - text string - valid bool -}{ - // supported by whatsapp - {"http://foo.com/blah_blah", true}, - {"http://foo.com/blah_blah/", true}, - {"http://foo.com/blah_blah_(wikipedia)", true}, - {"http://foo.com/blah_blah_(wikipedia)_(again)", true}, - {"http://www.example.com/wpstyle/?p=364", true}, - {"https://www.example.com/foo/?bar=baz&inga=42&quux", true}, - {"http://userid:password@example.com:8080", true}, - {"http://userid:password@example.com:8080/", true}, - {"http://userid@example.com", true}, - {"http://userid@example.com/", true}, - {"http://userid@example.com:8080", true}, - {"http://userid@example.com:8080/", true}, - {"http://userid:password@example.com", true}, - {"http://userid:password@example.com/", true}, - {"http://foo.com/blah_(wikipedia)#cite-1", true}, - {"http://foo.com/blah_(wikipedia)_blah#cite-1", true}, - {"http://foo.com/unicode_(✪)_in_parens", true}, - {"http://foo.com/(something)?after=parens", true}, - {"http://code.google.com/events/#&product=browser", true}, - {"http://foo.bar/?q=Test%20URL-encoded%20stuff", true}, - {"http://1337.net", true}, - {"http://a.b-c.de", true}, - {"http://foo.bar?q=Spaces foo bar", true}, - {"http://foo.bar/foo(bar)baz quux", true}, - {"http://a.b--c.de/", true}, - {"http://www.foo.bar./", true}, - // not supported by whatsapp - {"http://✪df.ws/123", false}, - {"http://142.42.1.1/", false}, - {"http://142.42.1.1:8080/", false}, - {"http://➡.ws/䨹", false}, - {"http://⌘.ws", false}, - {"http://⌘.ws/", false}, - {"http://☺.damowmow.com/", false}, - {"ftp://foo.bar/baz", false}, - {"http://مثال.إختبار", false}, - {"http://例子.测试", false}, - {"http://उदाहरण.परीक्षा", false}, - {"http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", false}, - {"http://223.255.255.254", false}, - {"https://foo_bar.example.com/", false}, - {"http://", false}, - {"http://.", false}, - {"http://..", false}, - {"http://../", false}, - {"http://?", false}, - {"http://??", false}, - {"http://??/", false}, - {"http://#", false}, - {"http://##", false}, - {"http://##/", false}, - {"//", false}, - {"//a", false}, - {"///a", false}, - {"///", false}, - {"http:///a", false}, - {"foo.com", false}, - {"rdar://1234", false}, - {"h://test", false}, - {"http:// shouldfail.com", false}, - {":// should fail", false}, - {"ftps://foo.bar/", false}, - {"http://-error-.invalid/", false}, - {"http://-a.b.co", false}, - {"http://a.b-.co", false}, - {"http://0.0.0.0", false}, - {"http://10.1.1.0", false}, - {"http://10.1.1.255", false}, - {"http://224.1.1.1", false}, - {"http://1.1.1.1.1", false}, - {"http://123.123.123", false}, - {"http://3628126748", false}, - {"http://.www.foo.bar/", false}, - {"http://.www.foo.bar./", false}, - {"http://10.1.1.1", false}, - {"http://10.1.1.254", false}, -} - -func TestUrlRegex(t *testing.T) { - for _, c := range urlTestCases { - if valid := urlRegex.MatchString(c.text); valid != c.valid { - t.Errorf(` - ERROR: Not equal: - text = %#v - expected: %t - actual : %t`, c.text, c.valid, valid) - } - } -} diff --git a/handlers/kannel/kannel_test.go b/handlers/kannel/kannel_test.go index a020e95d9..2a65f8ec1 100644 --- a/handlers/kannel/kannel_test.go +++ b/handlers/kannel/kannel_test.go @@ -10,19 +10,6 @@ import ( "github.com/nyaruka/courier/test" ) -var ( - receiveNoParams = "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/" - receiveValidMessage = "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?backend=NIG_MTN&sender=%2B2349067554729&message=Join&ts=1493735509&id=asdf-asdf&to=24453" - receiveKIMessage = "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?backend=NIG_MTN&sender=%2B68673076228&message=Join&ts=1493735509&id=asdf-asdf&to=24453" - receiveInvalidURN = "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?backend=NIG_MTN&sender=MTN&message=Join&ts=1493735509&id=asdf-asdf&to=24453" - receiveEmptyMessage = "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?backend=NIG_MTN&sender=%2B2349067554729&message=&ts=1493735509&id=asdf-asdf&to=24453" - statusNoParams = "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/" - statusInvalidStatus = "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/?id=12345&status=66" - statusWired = "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/?id=12345&status=4" - statusSent = "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/?id=12345&status=8" - statusDelivered = "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/?id=12345&status=1" -) - var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "KN", "2020", "US", nil), } @@ -32,25 +19,104 @@ var ignoreChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Receive KI Message", URL: receiveKIMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+68673076228", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Receive Empty Message", URL: receiveEmptyMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedMsgText: Sp(""), ExpectedURN: "tel:+2349067554729", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Receive No Params", URL: receiveNoParams, Data: "empty", ExpectedRespStatus: 400, ExpectedBodyContains: "field 'sender' required"}, - {Label: "Invalid URN", URL: receiveInvalidURN, Data: "empty", ExpectedRespStatus: 400, ExpectedBodyContains: "phone number supplied is not a number"}, - {Label: "Status No Params", URL: statusNoParams, ExpectedRespStatus: 400, ExpectedBodyContains: "field 'status' required"}, - {Label: "Status Invalid Status", URL: statusInvalidStatus, ExpectedRespStatus: 400, ExpectedBodyContains: "unknown status '66', must be one of 1,2,4,8,16"}, - {Label: "Status Valid", URL: statusWired, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"S"`, ExpectedMsgStatus: courier.MsgSent}, + { + Label: "Receive Valid Message", + URL: "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?backend=NIG_MTN&sender=%2B2349067554729&message=Join&ts=1493735509&id=asdf-asdf&to=24453", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + ExpectedExternalID: "asdf-asdf", + ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC), + }, + { + Label: "Receive KI Message", + URL: "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?backend=NIG_MTN&sender=%2B68673076228&message=Join&ts=1493735509&id=asdf-asdf&to=24453", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+68673076228", + ExpectedExternalID: "asdf-asdf", + ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC), + }, + { + Label: "Receive Empty Message", + URL: "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?backend=NIG_MTN&sender=%2B2349067554729&message=&ts=1493735509&id=asdf-asdf&to=24453", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedURN: "tel:+2349067554729", + ExpectedExternalID: "asdf-asdf", + ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC), + }, + { + Label: "Receive No Params", + URL: "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/", + Data: "empty", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'sender' required", + }, + { + Label: "Invalid URN", + URL: "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?backend=NIG_MTN&sender=MTN&message=Join&ts=1493735509&id=asdf-asdf&to=24453", + Data: "empty", + ExpectedRespStatus: 400, + ExpectedBodyContains: "phone number supplied is not a number", + }, + { + Label: "Status No Params", + URL: "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/", + ExpectedRespStatus: 400, + ExpectedBodyContains: "field 'status' required"}, + { + Label: "Status Invalid Status", + URL: "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/?id=12345&status=66", + ExpectedRespStatus: 400, + ExpectedBodyContains: "unknown status '66', must be one of 1,2,4,8,16", + }, + { + Label: "Status Valid", + URL: "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/?id=12345&status=4", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"S"`, + ExpectedMsgStatus: courier.MsgSent, + }, } var ignoreTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveValidMessage, Data: "empty", ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", ExpectedExternalID: "asdf-asdf", ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC)}, - {Label: "Write Status Delivered", URL: statusDelivered, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered}, - {Label: "Ignore Status Wired", URL: statusWired, ExpectedRespStatus: 200, ExpectedBodyContains: `ignoring sent report`}, - {Label: "Ignore Status Sent", URL: statusSent, ExpectedRespStatus: 200, ExpectedBodyContains: `ignoring sent report`}, + { + Label: "Receive Valid Message", + URL: "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive/?backend=NIG_MTN&sender=%2B2349067554729&message=Join&ts=1493735509&id=asdf-asdf&to=24453", + Data: "empty", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + ExpectedExternalID: "asdf-asdf", + ExpectedDate: time.Date(2017, 5, 2, 14, 31, 49, 0, time.UTC), + }, + { + Label: "Write Status Delivered", + URL: "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/?id=12345&status=1", + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"D"`, + ExpectedMsgStatus: courier.MsgDelivered, + }, + { + Label: "Ignore Status Wired", + URL: "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/?id=12345&status=4", + ExpectedRespStatus: 200, + ExpectedBodyContains: `ignoring sent report`, + }, + { + Label: "Ignore Status Sent", + URL: "/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status/?id=12345&status=8", + ExpectedRespStatus: 200, + ExpectedBodyContains: `ignoring sent report`, + }, } func TestHandler(t *testing.T) { @@ -73,58 +139,103 @@ func setSendURLWithQuery(s *httptest.Server, h courier.ChannelHandler, c courier } var defaultSendTestCases = []ChannelSendTestCase{ - {Label: "Plain Send", - MsgText: "Simple Message", MsgURN: "tel:+250788383383", MsgHighPriority: false, - ExpectedMsgStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"text": "Simple Message", "to": "+250788383383", "coding": "", "priority": "", - "dlr-url": "https://localhost/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%d"}, - SendPrep: setSendURL}, - {Label: "Unicode Send", - MsgText: "☺", MsgURN: "tel:+250788383383", MsgHighPriority: false, - ExpectedMsgStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"text": "☺", "to": "+250788383383", "coding": "2", "charset": "utf8", "priority": ""}, - SendPrep: setSendURL}, - {Label: "Smart Encoding", - MsgText: "Fancy “Smart” Quotes", MsgURN: "tel:+250788383383", MsgHighPriority: false, - ExpectedMsgStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"text": `Fancy "Smart" Quotes`, "to": "+250788383383", "coding": "", "priority": ""}, - SendPrep: setSendURL}, - {Label: "Not Routable", - MsgText: "Not Routable", MsgURN: "tel:+250788383383", MsgHighPriority: false, - ExpectedMsgStatus: "F", - MockResponseBody: "Not routable. Do not try again.", MockResponseStatus: 403, - ExpectedURLParams: map[string]string{"text": `Not Routable`, "to": "+250788383383", "coding": "", "priority": ""}, - SendPrep: setSendURL}, - {Label: "Error Sending", - MsgText: "Error Message", MsgURN: "tel:+250788383383", MsgHighPriority: false, - ExpectedMsgStatus: "E", - MockResponseBody: "1: Unknown channel", MockResponseStatus: 401, - ExpectedURLParams: map[string]string{"text": `Error Message`, "to": "+250788383383", "coding": "", "priority": ""}, - SendPrep: setSendURL}, - {Label: "Custom Params", - MsgText: "Custom Params", MsgURN: "tel:+250788383383", MsgHighPriority: true, - ExpectedMsgStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 201, - ExpectedURLParams: map[string]string{"text": `Custom Params`, "to": "+250788383383", "coding": "", "priority": "1", "auth": "foo"}, - SendPrep: setSendURLWithQuery}, - {Label: "Send Attachment", - MsgText: "My pic!", MsgURN: "tel:+250788383383", MsgHighPriority: true, MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - ExpectedMsgStatus: "W", - MockResponseBody: `0: Accepted for delivery`, MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "+250788383383", "from": "2020", "dlr-mask": "27"}, - SendPrep: setSendURL}, + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MsgHighPriority: false, + ExpectedMsgStatus: "W", + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{ + "text": "Simple Message", + "to": "+250788383383", + "coding": "", + "priority": "", + "dlr-url": "https://localhost/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%d", + }, + SendPrep: setSendURL, + }, + { + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "tel:+250788383383", + MsgHighPriority: false, + ExpectedMsgStatus: "W", + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "☺", "to": "+250788383383", "coding": "2", "charset": "utf8", "priority": ""}, + SendPrep: setSendURL, + }, + { + Label: "Smart Encoding", + MsgText: "Fancy “Smart” Quotes", + MsgURN: "tel:+250788383383", + MsgHighPriority: false, + ExpectedMsgStatus: "W", + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": `Fancy "Smart" Quotes`, "to": "+250788383383", "coding": "", "priority": ""}, + SendPrep: setSendURL}, + { + Label: "Not Routable", + MsgText: "Not Routable", + MsgURN: "tel:+250788383383", + MsgHighPriority: false, + ExpectedMsgStatus: "F", + MockResponseBody: "Not routable. Do not try again.", + MockResponseStatus: 403, + ExpectedURLParams: map[string]string{"text": `Not Routable`, "to": "+250788383383", "coding": "", "priority": ""}, + SendPrep: setSendURL, + }, + { + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MsgHighPriority: false, + ExpectedMsgStatus: "E", + MockResponseBody: "1: Unknown channel", + MockResponseStatus: 401, + ExpectedURLParams: map[string]string{"text": `Error Message`, "to": "+250788383383", "coding": "", "priority": ""}, + SendPrep: setSendURL, + }, + { + Label: "Custom Params", + MsgText: "Custom Params", + MsgURN: "tel:+250788383383", + MsgHighPriority: true, + ExpectedMsgStatus: "W", + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 201, + ExpectedURLParams: map[string]string{"text": `Custom Params`, "to": "+250788383383", "coding": "", "priority": "1", "auth": "foo"}, + SendPrep: setSendURLWithQuery, + }, + { + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgHighPriority: true, + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedMsgStatus: "W", + MockResponseBody: `0: Accepted for delivery`, + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "My pic!\nhttps://foo.bar/image.jpg", "to": "+250788383383", "from": "2020", "dlr-mask": "27"}, + SendPrep: setSendURL, + }, } var nationalSendTestCases = []ChannelSendTestCase{ - {Label: "National Send", - MsgText: "success", MsgURN: "tel:+250788383383", MsgHighPriority: true, - ExpectedMsgStatus: "W", - MockResponseBody: "0: Accepted for delivery", MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"text": "success", "to": "788383383", "coding": "", "priority": "1", "dlr-mask": "3"}, - SendPrep: setSendURL}, + { + Label: "National Send", + MsgText: "success", + MsgURN: "tel:+250788383383", + MsgHighPriority: true, + ExpectedMsgStatus: "W", + MockResponseBody: "0: Accepted for delivery", + MockResponseStatus: 200, + ExpectedURLParams: map[string]string{"text": "success", "to": "788383383", "coding": "", "priority": "1", "dlr-mask": "3"}, + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index 7851ceaa6..471a2290b 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -258,38 +258,120 @@ var testChannels = []courier.Channel{ } var handleTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedMsgText: Sp("Hello, world"), ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature}, - {Label: "Receive Valid Message", URL: receiveURL, Data: receiveValidMessageLast, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedMsgText: Sp("Last event"), ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature}, - - {Label: "Receive Valid Image Message", URL: receiveURL, Data: receiveValidImageMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature}, - {Label: "Receive Valid Video Message", URL: receiveURL, Data: receiveValidVideoMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature}, - {Label: "Receive Valid Video External Message", URL: receiveURL, Data: receiveValidVideoExternalMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://example.com/original.mp4"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature}, - {Label: "Receive Valid Audio Message", URL: receiveURL, Data: receiveValidAudioMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature}, - {Label: "Receive Valid Location Message", URL: receiveURL, Data: receiveValidLocationMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "Accepted", - ExpectedMsgText: Sp("my location"), ExpectedAttachments: []string{"geo:35.687574,139.729220"}, ExpectedURN: "line:uabcdefghij", ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), - PrepRequest: addValidSignature}, - - {Label: "Missing message", URL: receiveURL, Data: missingMessage, ExpectedRespStatus: 200, ExpectedBodyContains: "ignoring request, no message", - PrepRequest: addValidSignature}, - {Label: "Invalid URN", URL: receiveURL, Data: invalidURN, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid line id", - PrepRequest: addValidSignature}, - {Label: "No event request", URL: receiveURL, Data: noEvent, ExpectedRespStatus: 200, ExpectedBodyContains: "ignoring request, no message", - PrepRequest: addValidSignature}, - - {Label: "Receive Valid Message Invalid signature", URL: receiveURL, Data: receiveValidMessage, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid request signature", - PrepRequest: addInvalidSignature}, + { + Label: "Receive Valid Message", + URL: receiveURL, + Data: receiveValidMessage, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Hello, world"), + ExpectedURN: "line:uabcdefghij", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Message", + URL: receiveURL, + Data: receiveValidMessageLast, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Last event"), + ExpectedURN: "line:uabcdefghij", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Image Message", + URL: receiveURL, + Data: receiveValidImageMessage, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, + ExpectedURN: "line:uabcdefghij", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Video Message", + URL: receiveURL, + Data: receiveValidVideoMessage, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, + ExpectedURN: "line:uabcdefghij", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Video External Message", + URL: receiveURL, + Data: receiveValidVideoExternalMessage, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"https://example.com/original.mp4"}, + ExpectedURN: "line:uabcdefghij", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Audio Message", + URL: receiveURL, + Data: receiveValidAudioMessage, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"https://api-data.line.me/v2/bot/message/100001/content"}, + ExpectedURN: "line:uabcdefghij", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Location Message", + URL: receiveURL, + Data: receiveValidLocationMessage, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("my location"), + ExpectedAttachments: []string{"geo:35.687574,139.729220"}, + ExpectedURN: "line:uabcdefghij", + ExpectedDate: time.Date(2016, 4, 7, 1, 11, 27, 970000000, time.UTC), + PrepRequest: addValidSignature, + }, + { + Label: "Missing message", + URL: receiveURL, + Data: missingMessage, + ExpectedRespStatus: 200, + ExpectedBodyContains: "ignoring request, no message", + PrepRequest: addValidSignature, + }, + { + Label: "Invalid URN", + URL: receiveURL, + Data: invalidURN, + ExpectedRespStatus: 400, + ExpectedBodyContains: "invalid line id", + PrepRequest: addValidSignature, + }, + { + Label: "No event request", + URL: receiveURL, + Data: noEvent, + ExpectedRespStatus: 200, + ExpectedBodyContains: "ignoring request, no message", + PrepRequest: addValidSignature, + }, + { + Label: "Receive Valid Message Invalid signature", + URL: receiveURL, + Data: receiveValidMessage, + ExpectedRespStatus: 400, + ExpectedBodyContains: "invalid request signature", + PrepRequest: addInvalidSignature, + }, } func addValidSignature(r *http.Request) { diff --git a/handlers/utils.go b/handlers/utils.go index 13006ac6c..d967b2cf9 100644 --- a/handlers/utils.go +++ b/handlers/utils.go @@ -13,6 +13,10 @@ import ( "github.com/nyaruka/gocommon/urns" ) +var ( + urlRegex = regexp.MustCompile(`https?:\/\/(www\.)?[^\W][-a-zA-Z0-9@:%.\+~#=]{1,256}[^\W]\.[a-zA-Z()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)`) +) + // GetTextAndAttachments returns both the text of our message as well as any attachments, newline delimited func GetTextAndAttachments(m courier.Msg) string { buf := bytes.NewBuffer([]byte(m.Text())) @@ -143,3 +147,7 @@ func StrictTelForCountry(number string, country string) (urns.URN, error) { return urn, nil } + +func IsURL(s string) bool { + return urlRegex.MatchString(s) +} diff --git a/handlers/utils_test.go b/handlers/utils_test.go new file mode 100644 index 000000000..9ac5dd966 --- /dev/null +++ b/handlers/utils_test.go @@ -0,0 +1,97 @@ +package handlers_test + +import ( + "testing" + + "github.com/nyaruka/courier/handlers" + "github.com/stretchr/testify/assert" +) + +var urlTestCases = []struct { + text string + valid bool +}{ + // supported by whatsapp + {"http://foo.com/blah_blah", true}, + {"http://foo.com/blah_blah/", true}, + {"http://foo.com/blah_blah_(wikipedia)", true}, + {"http://foo.com/blah_blah_(wikipedia)_(again)", true}, + {"http://www.example.com/wpstyle/?p=364", true}, + {"https://www.example.com/foo/?bar=baz&inga=42&quux", true}, + {"http://userid:password@example.com:8080", true}, + {"http://userid:password@example.com:8080/", true}, + {"http://userid@example.com", true}, + {"http://userid@example.com/", true}, + {"http://userid@example.com:8080", true}, + {"http://userid@example.com:8080/", true}, + {"http://userid:password@example.com", true}, + {"http://userid:password@example.com/", true}, + {"http://foo.com/blah_(wikipedia)#cite-1", true}, + {"http://foo.com/blah_(wikipedia)_blah#cite-1", true}, + {"http://foo.com/unicode_(✪)_in_parens", true}, + {"http://foo.com/(something)?after=parens", true}, + {"http://code.google.com/events/#&product=browser", true}, + {"http://foo.bar/?q=Test%20URL-encoded%20stuff", true}, + {"http://1337.net", true}, + {"http://a.b-c.de", true}, + {"http://foo.bar?q=Spaces foo bar", true}, + {"http://foo.bar/foo(bar)baz quux", true}, + {"http://a.b--c.de/", true}, + {"http://www.foo.bar./", true}, + // not supported by whatsapp + {"http://✪df.ws/123", false}, + {"http://142.42.1.1/", false}, + {"http://142.42.1.1:8080/", false}, + {"http://➡.ws/䨹", false}, + {"http://⌘.ws", false}, + {"http://⌘.ws/", false}, + {"http://☺.damowmow.com/", false}, + {"ftp://foo.bar/baz", false}, + {"http://مثال.إختبار", false}, + {"http://例子.测试", false}, + {"http://उदाहरण.परीक्षा", false}, + {"http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", false}, + {"http://223.255.255.254", false}, + {"https://foo_bar.example.com/", false}, + {"http://", false}, + {"http://.", false}, + {"http://..", false}, + {"http://../", false}, + {"http://?", false}, + {"http://??", false}, + {"http://??/", false}, + {"http://#", false}, + {"http://##", false}, + {"http://##/", false}, + {"//", false}, + {"//a", false}, + {"///a", false}, + {"///", false}, + {"http:///a", false}, + {"foo.com", false}, + {"rdar://1234", false}, + {"h://test", false}, + {"http:// shouldfail.com", false}, + {":// should fail", false}, + {"ftps://foo.bar/", false}, + {"http://-error-.invalid/", false}, + {"http://-a.b.co", false}, + {"http://a.b-.co", false}, + {"http://0.0.0.0", false}, + {"http://10.1.1.0", false}, + {"http://10.1.1.255", false}, + {"http://224.1.1.1", false}, + {"http://1.1.1.1.1", false}, + {"http://123.123.123", false}, + {"http://3628126748", false}, + {"http://.www.foo.bar/", false}, + {"http://.www.foo.bar./", false}, + {"http://10.1.1.1", false}, + {"http://10.1.1.254", false}, +} + +func TestIsURL(t *testing.T) { + for _, tc := range urlTestCases { + assert.Equal(t, tc.valid, handlers.IsURL(tc.text), "isURL mimatch for input %s", tc.text) + } +} From 5f749a8791b7faf8d46da8fa1efe92c4a74a7a05 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 09:32:32 -0500 Subject: [PATCH 188/294] Update CHANGELOG.md for v7.5.32 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fbda062b..8ada637fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.32 +---------- + * Include requests to download attachments on the channel log for the incoming message + * Add support for better channel error reporting + v7.5.31 ---------- * Allow twiml channels to send multiple media urls per message From 7ae2b2077af548542165b1ae6f5c2b7793d0ca7b Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 13:13:07 -0500 Subject: [PATCH 189/294] Update deps --- go.mod | 12 ++++++------ go.sum | 23 ++++++++++++----------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index c46a3aa6c..7b2eb914e 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/dghubble/oauth1 v0.7.1 github.com/evalphobia/logrus_sentry v0.8.2 github.com/go-chi/chi v4.1.2+incompatible - github.com/gofrs/uuid v4.2.0+incompatible + github.com/gofrs/uuid v4.3.0+incompatible github.com/gomodule/redigo v1.8.9 github.com/gorilla/schema v1.2.0 github.com/jmoiron/sqlx v1.3.5 @@ -28,7 +28,7 @@ require ( require ( github.com/antchfx/xpath v1.2.1 // indirect - github.com/aws/aws-sdk-go v1.44.67 // indirect + github.com/aws/aws-sdk-go v1.44.105 // indirect github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/structs v1.1.0 // indirect @@ -36,7 +36,7 @@ require ( github.com/getsentry/raven-go v0.2.0 // indirect github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kr/pretty v0.3.0 // indirect @@ -45,11 +45,11 @@ require ( github.com/naoina/go-stringutil v0.1.0 // indirect github.com/naoina/toml v0.1.1 // indirect github.com/nyaruka/librato v1.0.0 // indirect - github.com/nyaruka/phonenumbers v1.1.0 // indirect + github.com/nyaruka/phonenumbers v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect - golang.org/x/net v0.0.0-20220728211354-c7608f3a8462 // indirect - golang.org/x/sys v0.0.0-20220731174439-a90be440212d // indirect + golang.org/x/net v0.0.0-20220923203811-8be639271d50 // indirect + golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25 // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/go.sum b/go.sum index 24e02beae..9ae007a8e 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/antchfx/xmlquery v1.3.12 h1:6TMGpdjpO/P8VhjnaYPXuqT3qyJ/VsqoyNTmJzNBT github.com/antchfx/xmlquery v1.3.12/go.mod h1:3w2RvQvTz+DaT5fSgsELkSJcdNgkmg6vuXDEuhdwsPQ= github.com/antchfx/xpath v1.2.1 h1:qhp4EW6aCOVr5XIkT+l6LJ9ck/JsUH/yyauNgTQkBF8= github.com/antchfx/xpath v1.2.1/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= -github.com/aws/aws-sdk-go v1.44.67 h1:+nxfXbMe8QUB6svLsuLYsp+WhZBKM26w62Zidir739A= -github.com/aws/aws-sdk-go v1.44.67/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.105 h1:UUwoD1PRKIj3ltrDUYTDQj5fOTK3XsnqolLpRTMmSEM= +github.com/aws/aws-sdk-go v1.44.105/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s= @@ -31,10 +31,11 @@ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/j github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= -github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= +github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= @@ -82,8 +83,8 @@ github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0 github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= github.com/nyaruka/null v1.2.0/go.mod h1:HSAFbLNOaEhHnoU0VCveCPz0GDtJ3GEtFWhvnBNkhPE= -github.com/nyaruka/phonenumbers v1.1.0 h1:OvNAOAl4A9a2kNpzziITbUVH4bBBeKHkHl0llPmkxaA= -github.com/nyaruka/phonenumbers v1.1.0/go.mod h1:cGaEsOrLjIL0iKGqJR5Rfywy86dSkbApEpXuM9KySNA= +github.com/nyaruka/phonenumbers v1.1.1 h1:fyoZmpLN2VCmAnc51XcrNOUVP2wT1ZzQl348ggIaXII= +github.com/nyaruka/phonenumbers v1.1.1/go.mod h1:cGaEsOrLjIL0iKGqJR5Rfywy86dSkbApEpXuM9KySNA= github.com/nyaruka/redisx v0.2.2 h1:OAJ4g1So2opn6O5akDWEWiDWgEOvPMKU10EUCG/Nv9Y= github.com/nyaruka/redisx v0.2.2/go.mod h1:cdbAm4y/+oFWu7qFzH2ERPeqRXJC2CtgRhwcBacM4Oc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= @@ -114,15 +115,15 @@ golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220728211354-c7608f3a8462 h1:UreQrH7DbFXSi9ZFox6FNT3WBooWmdANpU+IfkT1T4I= -golang.org/x/net v0.0.0-20220728211354-c7608f3a8462/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220923203811-8be639271d50 h1:vKyz8L3zkd+xrMeIaBsQ/MNVPVFSffdaU3ZyYlBGFnI= +golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220731174439-a90be440212d h1:Sv5ogFZatcgIMMtBSTTAgMYsicp25MXBubjXNDKwm80= -golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25 h1:nwzwVf0l2Y/lkov/+IYgMMbFyI+QypZDds9RxlSmsFQ= +golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= From 0de5985fd0794a0a812b88dd77b9fed7a77ebfd5 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 13:21:26 -0500 Subject: [PATCH 190/294] Add more detail to error message from S3 put --- backends/rapidpro/msg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index 3314525cc..9689c8569 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -328,7 +328,7 @@ func saveAttachmentToStorage(ctx context.Context, b *backend, orgID OrgID, msgUU s3URL, err := b.storage.Put(ctx, path, contentType, data) if err != nil { - return "", err + return "", errors.Wrapf(err, "error saving attachment to S3 (bytes=%d, path=%s)", len(data), path) } // return our new media URL, which is prefixed by our content type From 597a9f8657d729ac5323a8d3bf16228ad4837528 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 13:22:06 -0500 Subject: [PATCH 191/294] Update CHANGELOG.md for v7.5.33 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ada637fc..c5a84a4f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.33 +---------- + * Add more detail to error message from S3 put + * Update deps + v7.5.32 ---------- * Include requests to download attachments on the channel log for the incoming message From d685390c84577de7e2495c2fe4434da446991352 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 13:36:22 -0500 Subject: [PATCH 192/294] Tweak error message --- backends/rapidpro/msg.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index 9689c8569..b817303a8 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -326,9 +326,10 @@ func saveAttachmentToStorage(ctx context.Context, b *backend, orgID OrgID, msgUU path = fmt.Sprintf("/%s", path) } + start := time.Now() s3URL, err := b.storage.Put(ctx, path, contentType, data) if err != nil { - return "", errors.Wrapf(err, "error saving attachment to S3 (bytes=%d, path=%s)", len(data), path) + return "", errors.Wrapf(err, "error saving attachment to storage (bytes=%d, time=%dms)", len(data), time.Since(start)/time.Millisecond) } // return our new media URL, which is prefixed by our content type From 977cf60669c829ea78365a96cd55e50c05dbdd8a Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 13:36:45 -0500 Subject: [PATCH 193/294] Update CHANGELOG.md for v7.5.34 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5a84a4f3..53e8531c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.34 +---------- + * Tweak error message + v7.5.33 ---------- * Add more detail to error message from S3 put From 08cb5f691d0ccfd176f128966f1b058bfe870bea Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 14:32:34 -0500 Subject: [PATCH 194/294] More logging for large attachment downloads --- backends/rapidpro/msg.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index b817303a8..90b761fcb 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -248,6 +248,8 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie return "", err } + t0 := time.Now() + var req *http.Request handler := courier.GetHandler(channel.ChannelType()) if handler != nil { @@ -270,6 +272,8 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie } } + t1 := time.Now() + trace, err := httpx.DoTrace(utils.GetHTTPClient(), req, nil, nil, 100*1024*1024) if trace != nil { clog.HTTP(trace) @@ -278,6 +282,8 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie return "", err } + t2 := time.Now() + mimeType := "" extension := filepath.Ext(parsedURL.Path) if extension != "" { @@ -311,6 +317,11 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie } } + if len(trace.ResponseBody) > (10 * 1024 * 1024) { + t3 := time.Now() + logrus.WithField("Bytes", len(trace.ResponseBody)).WithField("T1", t1.Sub(t0)).WithField("T2", t2.Sub(t1)).WithField("T3", t3.Sub(t0)).Warn("Downloaded large attacment") + } + return saveAttachmentToStorage(ctx, b, orgID, msgUUID, mimeType, trace.ResponseBody, extension) } From a18e4a92124219b42b3c1b072c167f3e1e3e2966 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 14:37:49 -0500 Subject: [PATCH 195/294] Update CHANGELOG.md for v7.5.35 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53e8531c8..6ac249828 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.35 +---------- + * More logging for large attachment downloads + v7.5.34 ---------- * Tweak error message From 301a6e9d97a8dd07101623b63837d851fe370333 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 15:45:30 -0500 Subject: [PATCH 196/294] Update to latest gocommon and remove previous temp logging --- backends/rapidpro/msg.go | 11 ----------- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index 90b761fcb..b817303a8 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -248,8 +248,6 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie return "", err } - t0 := time.Now() - var req *http.Request handler := courier.GetHandler(channel.ChannelType()) if handler != nil { @@ -272,8 +270,6 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie } } - t1 := time.Now() - trace, err := httpx.DoTrace(utils.GetHTTPClient(), req, nil, nil, 100*1024*1024) if trace != nil { clog.HTTP(trace) @@ -282,8 +278,6 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie return "", err } - t2 := time.Now() - mimeType := "" extension := filepath.Ext(parsedURL.Path) if extension != "" { @@ -317,11 +311,6 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie } } - if len(trace.ResponseBody) > (10 * 1024 * 1024) { - t3 := time.Now() - logrus.WithField("Bytes", len(trace.ResponseBody)).WithField("T1", t1.Sub(t0)).WithField("T2", t2.Sub(t1)).WithField("T3", t3.Sub(t0)).Warn("Downloaded large attacment") - } - return saveAttachmentToStorage(ctx, b, orgID, msgUUID, mimeType, trace.ResponseBody, extension) } diff --git a/go.mod b/go.mod index 7b2eb914e..95037cdb4 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.6 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.30.0 + github.com/nyaruka/gocommon v1.30.1 github.com/nyaruka/null v1.2.0 github.com/nyaruka/redisx v0.2.2 github.com/patrickmn/go-cache v2.1.0+incompatible diff --git a/go.sum b/go.sum index 9ae007a8e..65da91f8c 100644 --- a/go.sum +++ b/go.sum @@ -77,8 +77,8 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.30.0 h1:394CU1fxGXSs+mrd5x8nXnqw2epT9P0ui/9MtSE2ycQ= -github.com/nyaruka/gocommon v1.30.0/go.mod h1:PApT/06fP5Tzs4/kbkJ+rVoyOc9Lbqm1lR0ow8Vqzp0= +github.com/nyaruka/gocommon v1.30.1 h1:W4n0GwTbcsI90vL7bpaCoGEtnc+fRn6FK/nTQtptrxw= +github.com/nyaruka/gocommon v1.30.1/go.mod h1:PApT/06fP5Tzs4/kbkJ+rVoyOc9Lbqm1lR0ow8Vqzp0= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= From 4d2f1e0e0328af11b71d098fcf1e0a38410ffef8 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 15:52:20 -0500 Subject: [PATCH 197/294] Update CHANGELOG.md for v7.5.36 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ac249828..6be00b6df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.36 +---------- + * Update to latest gocommon and remove previous temp logging + v7.5.35 ---------- * More logging for large attachment downloads From c38322e2c9cf89d7ed69ded8be3a6fbc2b1f35dc Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 16:29:21 -0500 Subject: [PATCH 198/294] Temp logging for large files --- backends/rapidpro/msg.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index b817303a8..afaca0da3 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -278,6 +278,17 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie return "", err } + // temp logging for large files + if len(trace.ResponseBody) > 25*1024*1024 { + var requestStart, deadline time.Time + asTime, isTime := ctx.Value(1).(time.Time) + if isTime { + requestStart = asTime + } + deadline, _ = ctx.Deadline() + logrus.WithContext(ctx).WithField("request_start", requestStart).WithField("deadline", deadline).WithField("bytes", len(trace.ResponseBody)).Warn("Large attachment") + } + mimeType := "" extension := filepath.Ext(parsedURL.Path) if extension != "" { From 19238f4e27bc6af3af88b15cb4cdda871b080864 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 16:37:17 -0500 Subject: [PATCH 199/294] Update CHANGELOG.md for v7.5.37 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6be00b6df..fc73f4b69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.37 +---------- + * Temp logging for large files + v7.5.36 ---------- * Update to latest gocommon and remove previous temp logging From 511dccc5246aaf7696e706db170020bbdd6900b0 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 16:57:12 -0500 Subject: [PATCH 200/294] Tweak large attachment logging --- backends/rapidpro/msg.go | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index afaca0da3..c21a9bec2 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -278,17 +278,6 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie return "", err } - // temp logging for large files - if len(trace.ResponseBody) > 25*1024*1024 { - var requestStart, deadline time.Time - asTime, isTime := ctx.Value(1).(time.Time) - if isTime { - requestStart = asTime - } - deadline, _ = ctx.Deadline() - logrus.WithContext(ctx).WithField("request_start", requestStart).WithField("deadline", deadline).WithField("bytes", len(trace.ResponseBody)).Warn("Large attachment") - } - mimeType := "" extension := filepath.Ext(parsedURL.Path) if extension != "" { @@ -337,6 +326,12 @@ func saveAttachmentToStorage(ctx context.Context, b *backend, orgID OrgID, msgUU path = fmt.Sprintf("/%s", path) } + // temp logging for large files + if len(data) > 25*1024*1024 { + deadline, _ := ctx.Deadline() + logrus.WithField("ctx_err", ctx.Err()).WithField("deadline", deadline).WithField("bytes", len(data)).Warn("Large attachment") + } + start := time.Now() s3URL, err := b.storage.Put(ctx, path, contentType, data) if err != nil { From 13c26252fb72c15d91282b05ff26e6e1106c3810 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 16:58:59 -0500 Subject: [PATCH 201/294] Update CHANGELOG.md for v7.5.38 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc73f4b69..2504df1d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.38 +---------- + * Tweak large attachment logging + v7.5.37 ---------- * Temp logging for large files From 9df71b65f8417860a0db5f504b2ef93ea02d9fc3 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 17:15:16 -0500 Subject: [PATCH 202/294] Tweak large attachment logging --- backends/rapidpro/backend.go | 6 ++++++ backends/rapidpro/msg.go | 18 +++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 0356cd849..63a5ffbd0 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -254,6 +254,12 @@ func (b *backend) MarkOutgoingMsgComplete(ctx context.Context, msg courier.Msg, // WriteMsg writes the passed in message to our store func (b *backend) WriteMsg(ctx context.Context, m courier.Msg, clog *courier.ChannelLog) error { + /////// temp logging /////// + if ctx.Err() != nil { + deadline, _ := ctx.Deadline() + logrus.WithField("ctx_err", ctx.Err()).WithField("deadline", deadline).Warn("Context cancelled") + } + timeout, cancel := context.WithTimeout(ctx, backendTimeout) defer cancel() diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index c21a9bec2..bffebb108 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -58,6 +58,12 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch return nil } + /////// temp logging /////// + if ctx.Err() != nil { + deadline, _ := ctx.Deadline() + logrus.WithField("ctx_err", ctx.Err()).WithField("deadline", deadline).Warn("Context cancelled") + } + channel := m.Channel() // if we have attachment URLs, download them to our own storage @@ -270,6 +276,12 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie } } + /////// temp logging /////// + if ctx.Err() != nil { + deadline, _ := ctx.Deadline() + logrus.WithField("ctx_err", ctx.Err()).WithField("deadline", deadline).Warn("Context cancelled") + } + trace, err := httpx.DoTrace(utils.GetHTTPClient(), req, nil, nil, 100*1024*1024) if trace != nil { clog.HTTP(trace) @@ -326,10 +338,10 @@ func saveAttachmentToStorage(ctx context.Context, b *backend, orgID OrgID, msgUU path = fmt.Sprintf("/%s", path) } - // temp logging for large files - if len(data) > 25*1024*1024 { + /////// temp logging /////// + if ctx.Err() != nil { deadline, _ := ctx.Deadline() - logrus.WithField("ctx_err", ctx.Err()).WithField("deadline", deadline).WithField("bytes", len(data)).Warn("Large attachment") + logrus.WithField("ctx_err", ctx.Err()).WithField("deadline", deadline).Warn("Context cancelled") } start := time.Now() From a03eb5d2d9b9fae9c52b08f27eb9c19128f59348 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 17:15:33 -0500 Subject: [PATCH 203/294] Update CHANGELOG.md for v7.5.39 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2504df1d1..d0083c8b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.39 +---------- + * Tweak large attachment logging + v7.5.38 ---------- * Tweak large attachment logging From 6e33c4f8bc455782cb57ef0b6dfe6c32813ffd85 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 18:45:39 -0500 Subject: [PATCH 204/294] Tweak temporary logging --- backends/rapidpro/backend.go | 6 ------ backends/rapidpro/msg.go | 20 +++++++------------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 63a5ffbd0..0356cd849 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -254,12 +254,6 @@ func (b *backend) MarkOutgoingMsgComplete(ctx context.Context, msg courier.Msg, // WriteMsg writes the passed in message to our store func (b *backend) WriteMsg(ctx context.Context, m courier.Msg, clog *courier.ChannelLog) error { - /////// temp logging /////// - if ctx.Err() != nil { - deadline, _ := ctx.Deadline() - logrus.WithField("ctx_err", ctx.Err()).WithField("deadline", deadline).Warn("Context cancelled") - } - timeout, cancel := context.WithTimeout(ctx, backendTimeout) defer cancel() diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index bffebb108..f4129062c 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -58,12 +58,6 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch return nil } - /////// temp logging /////// - if ctx.Err() != nil { - deadline, _ := ctx.Deadline() - logrus.WithField("ctx_err", ctx.Err()).WithField("deadline", deadline).Warn("Context cancelled") - } - channel := m.Channel() // if we have attachment URLs, download them to our own storage @@ -276,12 +270,6 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie } } - /////// temp logging /////// - if ctx.Err() != nil { - deadline, _ := ctx.Deadline() - logrus.WithField("ctx_err", ctx.Err()).WithField("deadline", deadline).Warn("Context cancelled") - } - trace, err := httpx.DoTrace(utils.GetHTTPClient(), req, nil, nil, 100*1024*1024) if trace != nil { clog.HTTP(trace) @@ -323,6 +311,12 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie } } + /////// temp logging /////// + if ctx.Err() != nil { + deadline, _ := ctx.Deadline() + logrus.WithField("ctx_err", ctx.Err()).WithField("deadline", deadline).Warn("Context cancelled 1") + } + return saveAttachmentToStorage(ctx, b, orgID, msgUUID, mimeType, trace.ResponseBody, extension) } @@ -341,7 +335,7 @@ func saveAttachmentToStorage(ctx context.Context, b *backend, orgID OrgID, msgUU /////// temp logging /////// if ctx.Err() != nil { deadline, _ := ctx.Deadline() - logrus.WithField("ctx_err", ctx.Err()).WithField("deadline", deadline).Warn("Context cancelled") + logrus.WithField("ctx_err", ctx.Err()).WithField("deadline", deadline).Warn("Context cancelled 2") } start := time.Now() From 979d0afec3caaf6745285ca6498bd3af4064ff14 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 26 Sep 2022 20:03:33 -0500 Subject: [PATCH 205/294] Remove temporary logging --- backends/rapidpro/msg.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index f4129062c..b817303a8 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -311,12 +311,6 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie } } - /////// temp logging /////// - if ctx.Err() != nil { - deadline, _ := ctx.Deadline() - logrus.WithField("ctx_err", ctx.Err()).WithField("deadline", deadline).Warn("Context cancelled 1") - } - return saveAttachmentToStorage(ctx, b, orgID, msgUUID, mimeType, trace.ResponseBody, extension) } @@ -332,12 +326,6 @@ func saveAttachmentToStorage(ctx context.Context, b *backend, orgID OrgID, msgUU path = fmt.Sprintf("/%s", path) } - /////// temp logging /////// - if ctx.Err() != nil { - deadline, _ := ctx.Deadline() - logrus.WithField("ctx_err", ctx.Err()).WithField("deadline", deadline).Warn("Context cancelled 2") - } - start := time.Now() s3URL, err := b.storage.Put(ctx, path, contentType, data) if err != nil { From b83afdb1fbb407393f3980fadf911d3c34575b6f Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Tue, 27 Sep 2022 17:01:59 +0200 Subject: [PATCH 206/294] All return 200 status for all WA webhook requests --- handlers/whatsapp/whatsapp.go | 5 +++++ handlers/whatsapp/whatsapp_test.go | 15 +++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index 5ce476d79..f462b5cb7 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -554,6 +554,11 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } +// WriteRequestError writes the passed in error to our response writer +func (h *handler) WriteRequestError(ctx context.Context, w http.ResponseWriter, err error) error { + return courier.WriteError(ctx, w, http.StatusOK, err) +} + func buildPayloads(msg courier.Msg, h *handler, clog *courier.ChannelLog) ([]interface{}, error) { var payloads []interface{} var err error diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index e783eea16..c6c224e6a 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -293,7 +293,10 @@ var ( var waTestCases = []ChannelHandleTestCase{ {Label: "Receive Valid Message", URL: waReceiveURL, Data: helloMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, - ExpectedContactName: Sp("Jerry Cooney"), ExpectedMsgText: Sp("hello world"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, + ExpectedContactName: Sp("Jerry Cooney"), ExpectedMsgText: Sp("hello world"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + NoQueueErrorCheck: true, + NoInvalidChannelCheck: true, + }, {Label: "Receive Duplicate Valid Message", URL: waReceiveURL, Data: duplicateMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, ExpectedMsgText: Sp("hello world"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Audio Message", URL: waReceiveURL, Data: audioMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, @@ -314,14 +317,14 @@ var waTestCases = []ChannelHandleTestCase{ ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, {Label: "Receive Valid Voice Message", URL: waReceiveURL, Data: voiceMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: invalidMsg, ExpectedRespStatus: 400, ExpectedBodyContains: "unable to parse"}, - {Label: "Receive Invalid From", URL: waReceiveURL, Data: invalidFrom, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid whatsapp id"}, - {Label: "Receive Invalid Timestamp", URL: waReceiveURL, Data: invalidTimestamp, ExpectedRespStatus: 400, ExpectedBodyContains: "invalid timestamp"}, + {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: invalidMsg, ExpectedRespStatus: 200, ExpectedBodyContains: "unable to parse"}, + {Label: "Receive Invalid From", URL: waReceiveURL, Data: invalidFrom, ExpectedRespStatus: 200, ExpectedBodyContains: "invalid whatsapp id"}, + {Label: "Receive Invalid Timestamp", URL: waReceiveURL, Data: invalidTimestamp, ExpectedRespStatus: 200, ExpectedBodyContains: "invalid timestamp"}, {Label: "Receive Valid Status", URL: waReceiveURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"status"`, ExpectedMsgStatus: "S", ExpectedExternalID: "9712A34B4A8B6AD50F"}, - {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: "not json", ExpectedRespStatus: 400, ExpectedBodyContains: "unable to parse"}, - {Label: "Receive Invalid Status", URL: waReceiveURL, Data: invalidStatus, ExpectedRespStatus: 400, ExpectedBodyContains: `"unknown status: in_orbit"`}, + {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: "not json", ExpectedRespStatus: 200, ExpectedBodyContains: "unable to parse"}, + {Label: "Receive Invalid Status", URL: waReceiveURL, Data: invalidStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `"unknown status: in_orbit"`}, {Label: "Receive Ignore Status", URL: waReceiveURL, Data: ignoreStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `"ignoring status: deleted"`}, } From 3e73ad246ab0b980154e8b1240868701834fb815 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 27 Sep 2022 10:24:16 -0500 Subject: [PATCH 207/294] Update CHANGELOG.md for v7.5.40 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0083c8b1..6553ca47e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.40 +---------- + * Always return 200 status for all WA webhook requests + * Remove temporary logging + v7.5.39 ---------- * Tweak large attachment logging From 346e17e0e07b11c490cb9d70624223604a01774a Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 27 Sep 2022 11:10:35 -0500 Subject: [PATCH 208/294] Allow handlers to provide a custom HTTP client for attachment fetches --- backends/rapidpro/msg.go | 31 ++++++++++-------------- handler.go | 7 +++--- handlers/facebookapp/facebookapp.go | 10 ++++++-- handlers/facebookapp/facebookapp_test.go | 6 ++--- handlers/jiochat/jiochat.go | 11 +++++++-- handlers/jiochat/jiochat_test.go | 2 +- handlers/line/line.go | 11 +++++++-- handlers/line/line_test.go | 2 +- handlers/rocketchat/rocketchat.go | 11 +++++++-- handlers/wechat/wechat.go | 11 +++++++-- handlers/wechat/wechat_test.go | 2 +- handlers/whatsapp/whatsapp.go | 10 ++++++-- handlers/whatsapp/whatsapp_test.go | 6 ++--- 13 files changed, 78 insertions(+), 42 deletions(-) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index b817303a8..e120c7f79 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -248,29 +248,24 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie return "", err } - var req *http.Request - handler := courier.GetHandler(channel.ChannelType()) - if handler != nil { - builder, isBuilder := handler.(courier.MediaDownloadRequestBuilder) - if isBuilder { - req, err = builder.BuildDownloadMediaRequest(ctx, b, channel, parsedURL.String()) + var httpClient *http.Client + var attRequest *http.Request - // in the case of errors, we log the error but move onwards anyways - if err != nil { - logrus.WithField("channel_uuid", channel.UUID()).WithField("channel_type", channel.ChannelType()).WithField("media_url", attURL).WithError(err).Error("unable to build attachment download request") - } - } + handler := courier.GetHandler(channel.ChannelType()) + builder, isBuilder := handler.(courier.AttachmentRequestBuilder) + if isBuilder { + httpClient = builder.AttachmentRequestClient() + attRequest, err = builder.BuildAttachmentRequest(ctx, b, channel, parsedURL.String()) + } else { + httpClient = utils.GetHTTPClient() + attRequest, err = http.NewRequest(http.MethodGet, attURL, nil) } - if req == nil { - // first fetch our media - req, err = http.NewRequest(http.MethodGet, attURL, nil) - if err != nil { - return "", err - } + if err != nil { + return "", errors.Wrap(err, "unable to create attachment request") } - trace, err := httpx.DoTrace(utils.GetHTTPClient(), req, nil, nil, 100*1024*1024) + trace, err := httpx.DoTrace(httpClient, attRequest, nil, nil, 100*1024*1024) if trace != nil { clog.HTTP(trace) } diff --git a/handler.go b/handler.go index 8816fd05f..14ad6542b 100644 --- a/handler.go +++ b/handler.go @@ -40,9 +40,10 @@ type URNDescriber interface { DescribeURN(context.Context, Channel, urns.URN, *ChannelLog) (map[string]string, error) } -// MediaDownloadRequestBuilder is the interface handlers which can allow a custom way to download attachment media for messages should satisfy -type MediaDownloadRequestBuilder interface { - BuildDownloadMediaRequest(context.Context, Backend, Channel, string) (*http.Request, error) +// AttachmentRequestBuilder is the interface handlers which can allow a custom way to download attachment media for messages should satisfy +type AttachmentRequestBuilder interface { + BuildAttachmentRequest(context.Context, Backend, Channel, string) (*http.Request, error) + AttachmentRequestClient() *http.Client } // RegisterHandler adds a new handler for a channel type, this is called by individual handlers when they are initialized diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 1932895a3..fdaaca47c 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -1443,8 +1443,8 @@ func (h *handler) getTemplate(msg courier.Msg) (*MsgTemplating, error) { return templating, err } -// BuildDownloadMediaRequest to download media for message attachment with Bearer token set -func (h *handler) BuildDownloadMediaRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { +// BuildAttachmentRequest to download media for message attachment with Bearer token set +func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { token := h.Server().Config().WhatsappAdminSystemUserToken if token == "" { return nil, fmt.Errorf("missing token for WAC channel") @@ -1459,6 +1459,12 @@ func (h *handler) BuildDownloadMediaRequest(ctx context.Context, b courier.Backe return req, nil } +func (*handler) AttachmentRequestClient() *http.Client { + return utils.GetHTTPClient() +} + +var _ courier.AttachmentRequestBuilder = (*handler)(nil) + type TemplateMetadata struct { Templating *MsgTemplating `json:"templating"` } diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 1990fa9db..166cdbcd5 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -1375,19 +1375,19 @@ func TestBuildMediaRequest(t *testing.T) { s := newServer(mb) wacHandler := &handler{NewBaseHandlerWithParams(courier.ChannelType("WAC"), "WhatsApp Cloud", false, nil)} wacHandler.Initialize(s) - req, _ := wacHandler.BuildDownloadMediaRequest(context.Background(), mb, testChannelsWAC[0], "https://example.org/v1/media/41") + req, _ := wacHandler.BuildAttachmentRequest(context.Background(), mb, testChannelsWAC[0], "https://example.org/v1/media/41") assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, "Bearer wac_admin_system_user_token", req.Header.Get("Authorization")) fbaHandler := &handler{NewBaseHandlerWithParams(courier.ChannelType("FBA"), "Facebook", false, nil)} fbaHandler.Initialize(s) - req, _ = fbaHandler.BuildDownloadMediaRequest(context.Background(), mb, testChannelsFBA[0], "https://example.org/v1/media/41") + req, _ = fbaHandler.BuildAttachmentRequest(context.Background(), mb, testChannelsFBA[0], "https://example.org/v1/media/41") assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, http.Header{}, req.Header) igHandler := &handler{NewBaseHandlerWithParams(courier.ChannelType("IG"), "Instagram", false, nil)} igHandler.Initialize(s) - req, _ = igHandler.BuildDownloadMediaRequest(context.Background(), mb, testChannelsFBA[0], "https://example.org/v1/media/41") + req, _ = igHandler.BuildAttachmentRequest(context.Background(), mb, testChannelsFBA[0], "https://example.org/v1/media/41") assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, http.Header{}, req.Header) } diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 380fcc945..5e49fd808 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -18,6 +18,7 @@ import ( "github.com/gomodule/redigo/redis" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/jsonx" "github.com/nyaruka/gocommon/urns" "github.com/sirupsen/logrus" @@ -296,8 +297,8 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn return map[string]string{"name": nickname}, nil } -// BuildDownloadMediaRequest download media for message attachment -func (h *handler) BuildDownloadMediaRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { +// BuildAttachmentRequest download media for message attachment +func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { parsedURL, err := url.Parse(attachmentURL) if err != nil { return nil, err @@ -313,3 +314,9 @@ func (h *handler) BuildDownloadMediaRequest(ctx context.Context, b courier.Backe req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken)) return req, nil } + +func (*handler) AttachmentRequestClient() *http.Client { + return utils.GetHTTPClient() +} + +var _ courier.AttachmentRequestBuilder = (*handler)(nil) diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index ce2376c1a..3bf426925 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -378,7 +378,7 @@ func TestBuildMediaRequest(t *testing.T) { } for _, tc := range tcs { - req, _ := handler.BuildDownloadMediaRequest(context.Background(), mb, testChannels[0], tc.url) + req, _ := handler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], tc.url) assert.Equal(t, tc.url, req.URL.String()) assert.Equal(t, tc.authorizationHeader, req.Header.Get("Authorization")) } diff --git a/handlers/line/line.go b/handlers/line/line.go index 3320e1ea4..1a12917ff 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -16,6 +16,7 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" "github.com/pkg/errors" ) @@ -181,8 +182,8 @@ func buildMediaURL(mediaID string) string { return mediaURL.String() } -// BuildDownloadMediaRequest to download media for message attachment with Bearer token set -func (h *handler) BuildDownloadMediaRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { +// BuildAttachmentRequest to download media for message attachment with Bearer token set +func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { token := channel.StringConfigForKey(courier.ConfigAuthToken, "") if token == "" { return nil, fmt.Errorf("missing token for LN channel") @@ -194,6 +195,12 @@ func (h *handler) BuildDownloadMediaRequest(ctx context.Context, b courier.Backe return req, nil } +func (*handler) AttachmentRequestClient() *http.Client { + return utils.GetHTTPClient() +} + +var _ courier.AttachmentRequestBuilder = (*handler)(nil) + func (h *handler) validateSignature(channel courier.Channel, r *http.Request) error { actual := r.Header.Get(signatureHeader) if actual == "" { diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index 471a2290b..a6dd4b46c 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -608,7 +608,7 @@ func TestBuildMediaRequest(t *testing.T) { mb := test.NewMockBackend() lnHandler := &handler{NewBaseHandler(courier.ChannelType("LN"), "Line")} - req, _ := lnHandler.BuildDownloadMediaRequest(context.Background(), mb, testChannels[0], "https://example.org/v1/media/41") + req, _ := lnHandler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], "https://example.org/v1/media/41") assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, "Bearer the-auth-token", req.Header.Get("Authorization")) } diff --git a/handlers/rocketchat/rocketchat.go b/handlers/rocketchat/rocketchat.go index 56ecd168f..1a89cc71c 100644 --- a/handlers/rocketchat/rocketchat.go +++ b/handlers/rocketchat/rocketchat.go @@ -11,6 +11,7 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" ) @@ -88,8 +89,8 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } -// BuildDownloadMediaRequest download media for message attachment with RC auth_token/user_id set -func (h *handler) BuildDownloadMediaRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { +// BuildAttachmentRequest download media for message attachment with RC auth_token/user_id set +func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { adminAuthToken := channel.StringConfigForKey(configAdminAuthToken, "") adminUserID := channel.StringConfigForKey(configAdminUserID, "") if adminAuthToken == "" || adminUserID == "" { @@ -102,6 +103,12 @@ func (h *handler) BuildDownloadMediaRequest(ctx context.Context, b courier.Backe return req, nil } +func (*handler) AttachmentRequestClient() *http.Client { + return utils.GetHTTPClient() +} + +var _ courier.AttachmentRequestBuilder = (*handler)(nil) + type mtPayload struct { UserURN string `json:"user"` BotUsername string `json:"bot"` diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index dbf44819f..d64c482d5 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -18,6 +18,7 @@ import ( "github.com/gomodule/redigo/redis" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" "github.com/sirupsen/logrus" ) @@ -310,8 +311,8 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn return map[string]string{"name": nickname}, nil } -// BuildDownloadMediaRequest download media for message attachment -func (h *handler) BuildDownloadMediaRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { +// BuildAttachmentRequest download media for message attachment +func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { accessToken, err := h.getAccessToken(channel) if err != nil { return nil, err @@ -329,3 +330,9 @@ func (h *handler) BuildDownloadMediaRequest(ctx context.Context, b courier.Backe req, _ := http.NewRequest(http.MethodGet, parsedURL.String(), nil) return req, nil } + +func (*handler) AttachmentRequestClient() *http.Client { + return utils.GetHTTPClient() +} + +var _ courier.AttachmentRequestBuilder = (*handler)(nil) diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index 19fd459c8..798ed062a 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -322,7 +322,7 @@ func TestBuildMediaRequest(t *testing.T) { } for _, tc := range tcs { - req, _ := handler.BuildDownloadMediaRequest(context.Background(), mb, testChannels[0], tc.url) + req, _ := handler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], tc.url) assert.Equal(t, fmt.Sprintf("%s/media/get?access_token=ACCESS_TOKEN&media_id=12", sendURL), req.URL.String()) } diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index f462b5cb7..9a4f237be 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -308,8 +308,8 @@ func resolveMediaURL(channel courier.Channel, mediaID string) (string, error) { return fileURL, nil } -// BuildDownloadMediaRequest to download media for message attachment with Bearer token set -func (h *handler) BuildDownloadMediaRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { +// BuildAttachmentRequest to download media for message attachment with Bearer token set +func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { token := channel.StringConfigForKey(courier.ConfigAuthToken, "") if token == "" { return nil, fmt.Errorf("missing token for WA channel") @@ -322,6 +322,12 @@ func (h *handler) BuildDownloadMediaRequest(ctx context.Context, b courier.Backe return req, nil } +func (*handler) AttachmentRequestClient() *http.Client { + return utils.GetHTTPClient() +} + +var _ courier.AttachmentRequestBuilder = (*handler)(nil) + var waStatusMapping = map[string]courier.MsgStatusValue{ "sending": courier.MsgWired, "sent": courier.MsgSent, diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index c6c224e6a..fbc50cf34 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -332,17 +332,17 @@ func TestBuildMediaRequest(t *testing.T) { mb := test.NewMockBackend() waHandler := &handler{NewBaseHandler(courier.ChannelType("WA"), "WhatsApp")} - req, _ := waHandler.BuildDownloadMediaRequest(context.Background(), mb, testChannels[0], "https://example.org/v1/media/41") + req, _ := waHandler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], "https://example.org/v1/media/41") assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, "Bearer the-auth-token", req.Header.Get("Authorization")) d3Handler := &handler{NewBaseHandler(courier.ChannelType("D3"), "360Dialog")} - req, _ = d3Handler.BuildDownloadMediaRequest(context.Background(), mb, testChannels[1], "https://example.org/v1/media/41") + req, _ = d3Handler.BuildAttachmentRequest(context.Background(), mb, testChannels[1], "https://example.org/v1/media/41") assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, "the-auth-token", req.Header.Get("D360-API-KEY")) txHandler := &handler{NewBaseHandler(courier.ChannelType("TXW"), "TextIt")} - req, _ = txHandler.BuildDownloadMediaRequest(context.Background(), mb, testChannels[0], "https://example.org/v1/media/41") + req, _ = txHandler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], "https://example.org/v1/media/41") assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, "Bearer the-auth-token", req.Header.Get("Authorization")) } From 02e16cae2867daccadf1a1334706f0f079dd91f0 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 27 Sep 2022 11:19:28 -0500 Subject: [PATCH 209/294] Customize the http client for D3 attachment fetches to have a timeout of 3 secs --- backends/rapidpro/msg.go | 2 +- handler.go | 2 +- handlers/facebookapp/facebookapp.go | 2 +- handlers/jiochat/jiochat.go | 2 +- handlers/line/line.go | 2 +- handlers/rocketchat/rocketchat.go | 2 +- handlers/wechat/wechat.go | 2 +- handlers/whatsapp/whatsapp.go | 14 +++++++++++--- 8 files changed, 18 insertions(+), 10 deletions(-) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index e120c7f79..dbd220e42 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -254,7 +254,7 @@ func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courie handler := courier.GetHandler(channel.ChannelType()) builder, isBuilder := handler.(courier.AttachmentRequestBuilder) if isBuilder { - httpClient = builder.AttachmentRequestClient() + httpClient = builder.AttachmentRequestClient(channel) attRequest, err = builder.BuildAttachmentRequest(ctx, b, channel, parsedURL.String()) } else { httpClient = utils.GetHTTPClient() diff --git a/handler.go b/handler.go index 14ad6542b..704604d7e 100644 --- a/handler.go +++ b/handler.go @@ -43,7 +43,7 @@ type URNDescriber interface { // AttachmentRequestBuilder is the interface handlers which can allow a custom way to download attachment media for messages should satisfy type AttachmentRequestBuilder interface { BuildAttachmentRequest(context.Context, Backend, Channel, string) (*http.Request, error) - AttachmentRequestClient() *http.Client + AttachmentRequestClient(Channel) *http.Client } // RegisterHandler adds a new handler for a channel type, this is called by individual handlers when they are initialized diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index fdaaca47c..f58ddf7f9 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -1459,7 +1459,7 @@ func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, return req, nil } -func (*handler) AttachmentRequestClient() *http.Client { +func (*handler) AttachmentRequestClient(ch courier.Channel) *http.Client { return utils.GetHTTPClient() } diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 5e49fd808..4edf4a93c 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -315,7 +315,7 @@ func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, return req, nil } -func (*handler) AttachmentRequestClient() *http.Client { +func (*handler) AttachmentRequestClient(ch courier.Channel) *http.Client { return utils.GetHTTPClient() } diff --git a/handlers/line/line.go b/handlers/line/line.go index 1a12917ff..bdc1e3341 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -195,7 +195,7 @@ func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, return req, nil } -func (*handler) AttachmentRequestClient() *http.Client { +func (*handler) AttachmentRequestClient(ch courier.Channel) *http.Client { return utils.GetHTTPClient() } diff --git a/handlers/rocketchat/rocketchat.go b/handlers/rocketchat/rocketchat.go index 1a89cc71c..ee01a95f1 100644 --- a/handlers/rocketchat/rocketchat.go +++ b/handlers/rocketchat/rocketchat.go @@ -103,7 +103,7 @@ func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, return req, nil } -func (*handler) AttachmentRequestClient() *http.Client { +func (*handler) AttachmentRequestClient(ch courier.Channel) *http.Client { return utils.GetHTTPClient() } diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index d64c482d5..61b58bdb9 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -331,7 +331,7 @@ func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, return req, nil } -func (*handler) AttachmentRequestClient() *http.Client { +func (*handler) AttachmentRequestClient(ch courier.Channel) *http.Client { return utils.GetHTTPClient() } diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index 9a4f237be..44995f75a 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -42,9 +42,11 @@ const ( var ( retryParam = "" -) -var failedMediaCache *cache.Cache + failedMediaCache *cache.Cache + + d360AttachmentClient *http.Client +) func init() { courier.RegisterHandler(newWAHandler(courier.ChannelType(channelTypeWa), "WhatsApp")) @@ -52,6 +54,9 @@ func init() { courier.RegisterHandler(newWAHandler(courier.ChannelType(channelTypeTXW), "TextIt")) failedMediaCache = cache.New(15*time.Minute, 15*time.Minute) + + // seems that we get about 5 seconds to respond to Dialog360 so we can't spend long fetching attachments + d360AttachmentClient = &http.Client{Timeout: time.Second * 3} } type handler struct { @@ -322,7 +327,10 @@ func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, return req, nil } -func (*handler) AttachmentRequestClient() *http.Client { +func (*handler) AttachmentRequestClient(ch courier.Channel) *http.Client { + if ch.ChannelType() == channelTypeD3 { + return d360AttachmentClient + } return utils.GetHTTPClient() } From 3c3cba57a9ef1f2c517585bdf17577146362f405 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 27 Sep 2022 11:42:37 -0500 Subject: [PATCH 210/294] Update CHANGELOG.md for v7.5.41 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6553ca47e..beccc978d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.41 +---------- + * Customize the http client for D3 attachment fetches to have a timeout of 3 secs + v7.5.40 ---------- * Always return 200 status for all WA webhook requests From 36ac3e5cacbb77c939614d1ae70161ee0808db56 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 28 Sep 2022 14:17:55 -0500 Subject: [PATCH 211/294] More jsonx.MustMarshal --- backends/rapidpro/task.go | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/backends/rapidpro/task.go b/backends/rapidpro/task.go index b13808cbe..184d62f8d 100644 --- a/backends/rapidpro/task.go +++ b/backends/rapidpro/task.go @@ -1,12 +1,12 @@ package rapidpro import ( - "encoding/json" "fmt" "time" "github.com/gomodule/redigo/redis" "github.com/nyaruka/courier" + "github.com/nyaruka/gocommon/jsonx" ) func queueMsgHandling(rc redis.Conn, c *DBContact, m *DBMsg) error { @@ -86,32 +86,20 @@ func queueChannelEvent(rc redis.Conn, c *DBContact, e *DBChannelEvent) error { // channel event tasks through the same ordered queue. func queueMailroomTask(rc redis.Conn, taskType string, orgID OrgID, contactID ContactID, body map[string]interface{}) (err error) { // create our event task - eventTask := mrTask{ + eventJSON := jsonx.MustMarshal(mrTask{ Type: taskType, OrgID: orgID, Task: body, QueuedOn: time.Now(), - } - - eventJSON, err := json.Marshal(eventTask) - if err != nil { - return err - } + }) // create our org task - contactTask := mrTask{ - Type: "handle_contact_event", - OrgID: orgID, - Task: mrContactTask{ - ContactID: contactID, - }, + contactJSON := jsonx.MustMarshal(mrTask{ + Type: "handle_contact_event", + OrgID: orgID, + Task: mrContactTask{ContactID: contactID}, QueuedOn: time.Now(), - } - - contactJSON, err := json.Marshal(contactTask) - if err != nil { - return err - } + }) now := time.Now().UTC() epochFloat := float64(now.UnixNano()) / float64(time.Second) From 2d19692deb49d88b8ed94d7176c08e6cbb67ea65 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 29 Sep 2022 12:01:29 -0500 Subject: [PATCH 212/294] Add channel UUID and type to queued msg events --- backends/rapidpro/backend_test.go | 2 ++ backends/rapidpro/task.go | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 0732d1c8c..673a490d5 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -1216,6 +1216,8 @@ func (ts *BackendTestSuite) TestWriteMsg() { "contact_id": float64(contact.ID_), "org_id": float64(1), "channel_id": float64(10), + "channel_uuid": "dbc126ed-66bc-4e28-b67b-81dc3327c95d", + "channel_type": "KN", "msg_id": float64(msg.ID_), "msg_uuid": msg.UUID_.String(), "msg_external_id": msg.ExternalID(), diff --git a/backends/rapidpro/task.go b/backends/rapidpro/task.go index 184d62f8d..02f1aee48 100644 --- a/backends/rapidpro/task.go +++ b/backends/rapidpro/task.go @@ -13,10 +13,12 @@ func queueMsgHandling(rc redis.Conn, c *DBContact, m *DBMsg) error { channel := m.Channel().(*DBChannel) // queue to mailroom - body := map[string]interface{}{ + body := map[string]any{ "contact_id": c.ID_, "org_id": channel.OrgID_, - "channel_id": channel.ID_, + "channel_id": channel.ID_, // deprecated + "channel_uuid": channel.UUID_, + "channel_type": channel.ChannelType_, "msg_id": m.ID_, "msg_uuid": m.UUID_.String(), "msg_external_id": m.ExternalID(), From a424b26e2771c28a95bb8b79c261cd236b1ad065 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 29 Sep 2022 14:52:58 -0500 Subject: [PATCH 213/294] Update CHANGELOG.md for v7.5.42 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index beccc978d..ea563d73e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.42 +---------- + * Add channel UUID and type to queued msg events + * More jsonx.MustMarshal + v7.5.41 ---------- * Customize the http client for D3 attachment fetches to have a timeout of 3 secs From 3187592ef4a3ea6c99d3736377c28e406a3bc8d1 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 4 Oct 2022 10:51:03 -0500 Subject: [PATCH 214/294] Add endpoint to download and store attachments by their URL --- attachments.go | 85 ++++++++++++++++++++++++ attachments_test.go | 7 ++ backend.go | 4 ++ backends/rapidpro/backend.go | 26 ++++++++ backends/rapidpro/backend_test.go | 2 +- backends/rapidpro/msg.go | 104 +----------------------------- channel_log.go | 20 ++++-- channel_log_test.go | 4 +- handlers/jiochat/jiochat.go | 2 +- handlers/wechat/wechat.go | 2 +- server.go | 50 +++++++++++++- test/backend.go | 5 ++ 12 files changed, 196 insertions(+), 115 deletions(-) create mode 100644 attachments.go create mode 100644 attachments_test.go diff --git a/attachments.go b/attachments.go new file mode 100644 index 000000000..3e7974ce4 --- /dev/null +++ b/attachments.go @@ -0,0 +1,85 @@ +package courier + +import ( + "context" + "mime" + "net/http" + "net/url" + "path/filepath" + + "github.com/nyaruka/courier/utils" + "github.com/nyaruka/gocommon/httpx" + "github.com/pkg/errors" + "gopkg.in/h2non/filetype.v1" +) + +const ( + maxAttBodyReadBytes = 100 * 1024 * 1024 +) + +func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, attURL string, clog *ChannelLog) (string, error) { + parsedURL, err := url.Parse(attURL) + if err != nil { + return "", err + } + + var httpClient *http.Client + var attRequest *http.Request + + handler := GetHandler(channel.ChannelType()) + builder, isBuilder := handler.(AttachmentRequestBuilder) + if isBuilder { + httpClient = builder.AttachmentRequestClient(channel) + attRequest, err = builder.BuildAttachmentRequest(ctx, b, channel, parsedURL.String()) + } else { + httpClient = utils.GetHTTPClient() + attRequest, err = http.NewRequest(http.MethodGet, attURL, nil) + } + + if err != nil { + return "", errors.Wrap(err, "unable to create attachment request") + } + + trace, err := httpx.DoTrace(httpClient, attRequest, nil, nil, maxAttBodyReadBytes) + if trace != nil { + clog.HTTP(trace) + } + if err != nil { + return "", err + } + + mimeType := "" + extension := filepath.Ext(parsedURL.Path) + if extension != "" { + extension = extension[1:] + } + + // first try getting our mime type from the first 300 bytes of our body + fileType, _ := filetype.Match(trace.ResponseBody[:300]) + if fileType != filetype.Unknown { + mimeType = fileType.MIME.Value + extension = fileType.Extension + } else { + // if that didn't work, try from our extension + fileType = filetype.GetType(extension) + if fileType != filetype.Unknown { + mimeType = fileType.MIME.Value + extension = fileType.Extension + } + } + + // we still don't know our mime type, use our content header instead + if mimeType == "" { + mimeType, _, _ = mime.ParseMediaType(trace.Response.Header.Get("Content-Type")) + if extension == "" { + extensions, err := mime.ExtensionsByType(mimeType) + if extensions == nil || err != nil { + extension = "" + } else { + extension = extensions[0][1:] + } + } + } + + return b.SaveAttachment(ctx, channel, mimeType, trace.ResponseBody, extension) +} diff --git a/attachments_test.go b/attachments_test.go new file mode 100644 index 000000000..0bee4495f --- /dev/null +++ b/attachments_test.go @@ -0,0 +1,7 @@ +package courier_test + +import "testing" + +func TestFetchAndStoreAttachment(t *testing.T) { + // TODO +} diff --git a/backend.go b/backend.go index 9ba79e93b..49f88f026 100644 --- a/backend.go +++ b/backend.go @@ -88,6 +88,10 @@ type Backend interface { // Mark a external ID as seen for a period WriteExternalIDSeen(Msg) + // SaveAttachment saves an attachment to backend storage + SaveAttachment(context.Context, Channel, string, []byte, string) (string, error) + + // ResolveMedia resolves an outgoing attachment URL to a media object ResolveMedia(context.Context, string) (Media, error) // Health returns a string describing any health problems the backend has, or empty string if all is well diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 0356cd849..91a657e81 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -8,7 +8,9 @@ import ( "fmt" "net/url" "path" + "path/filepath" "regexp" + "strconv" "strings" "sync" "time" @@ -404,6 +406,30 @@ func (b *backend) WriteExternalIDSeen(msg courier.Msg) { writeExternalIDSeen(b, msg) } +// SaveAttachment saves an attachment to backend storage +func (b *backend) SaveAttachment(ctx context.Context, ch courier.Channel, contentType string, data []byte, extension string) (string, error) { + // create our filename + filename := string(uuids.New()) + if extension != "" { + filename = fmt.Sprintf("%s.%s", filename, extension) + } + + orgID := ch.(*DBChannel).OrgID() + + path := filepath.Join(b.config.S3AttachmentsPrefix, strconv.FormatInt(int64(orgID), 10), filename[:4], filename[4:8], filename) + if !strings.HasPrefix(path, "/") { + path = fmt.Sprintf("/%s", path) + } + + s3URL, err := b.storage.Put(ctx, path, contentType, data) + if err != nil { + return "", errors.Wrapf(err, "error saving attachment to storage (bytes=%d)", len(data)) + } + + // return our new media URL, which is prefixed by our content type + return fmt.Sprintf("%s:%s", contentType, s3URL), nil +} + // ResolveMedia resolves the passed in attachment URL to a media object func (b *backend) ResolveMedia(ctx context.Context, mediaUrl string) (courier.Media, error) { u, err := url.Parse(mediaUrl) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 673a490d5..83f0e534b 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -1001,7 +1001,7 @@ func (ts *BackendTestSuite) TestWriteChanneLog() { trace, err := httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) ts.NoError(err) - clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel, nil) + clog := courier.NewChannelLog(courier.ChannelLogTypeTokenRefresh, channel, nil) clog.HTTP(trace) clog.RawError(errors.New("this is an error")) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index dbd220e42..730f229bc 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -6,12 +6,7 @@ import ( "encoding/json" "fmt" "log" - "mime" - "net/http" - "net/url" "os" - "path/filepath" - "strconv" "strings" "time" @@ -20,8 +15,6 @@ import ( "github.com/lib/pq" "github.com/nyaruka/courier" "github.com/nyaruka/courier/queue" - "github.com/nyaruka/courier/utils" - "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/urns" "github.com/nyaruka/null" "github.com/pkg/errors" @@ -66,7 +59,7 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch var err error if strings.HasPrefix(attURL, "http://") || strings.HasPrefix(attURL, "https://") { - newURL, err = downloadAttachmentToStorage(ctx, b, channel, m.OrgID_, m.UUID_, attURL, clog) + newURL, err = courier.FetchAndStoreAttachment(ctx, b, channel, attURL, clog) if err != nil { return err } @@ -87,7 +80,7 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch extension = "bin" } - newURL, err = saveAttachmentToStorage(ctx, b, m.OrgID_, m.UUID_, contentType, attData, extension) + newURL, err = b.SaveAttachment(ctx, channel, contentType, attData, extension) if err != nil { return err } @@ -238,99 +231,6 @@ WHERE ch.id = $1 ` -//----------------------------------------------------------------------------- -// Attachment download and classification -//----------------------------------------------------------------------------- - -func downloadAttachmentToStorage(ctx context.Context, b *backend, channel courier.Channel, orgID OrgID, msgUUID courier.MsgUUID, attURL string, clog *courier.ChannelLog) (string, error) { - parsedURL, err := url.Parse(attURL) - if err != nil { - return "", err - } - - var httpClient *http.Client - var attRequest *http.Request - - handler := courier.GetHandler(channel.ChannelType()) - builder, isBuilder := handler.(courier.AttachmentRequestBuilder) - if isBuilder { - httpClient = builder.AttachmentRequestClient(channel) - attRequest, err = builder.BuildAttachmentRequest(ctx, b, channel, parsedURL.String()) - } else { - httpClient = utils.GetHTTPClient() - attRequest, err = http.NewRequest(http.MethodGet, attURL, nil) - } - - if err != nil { - return "", errors.Wrap(err, "unable to create attachment request") - } - - trace, err := httpx.DoTrace(httpClient, attRequest, nil, nil, 100*1024*1024) - if trace != nil { - clog.HTTP(trace) - } - if err != nil { - return "", err - } - - mimeType := "" - extension := filepath.Ext(parsedURL.Path) - if extension != "" { - extension = extension[1:] - } - - // first try getting our mime type from the first 300 bytes of our body - fileType, _ := filetype.Match(trace.ResponseBody[:300]) - if fileType != filetype.Unknown { - mimeType = fileType.MIME.Value - extension = fileType.Extension - } else { - // if that didn't work, try from our extension - fileType = filetype.GetType(extension) - if fileType != filetype.Unknown { - mimeType = fileType.MIME.Value - extension = fileType.Extension - } - } - - // we still don't know our mime type, use our content header instead - if mimeType == "" { - mimeType, _, _ = mime.ParseMediaType(trace.Response.Header.Get("Content-Type")) - if extension == "" { - extensions, err := mime.ExtensionsByType(mimeType) - if extensions == nil || err != nil { - extension = "" - } else { - extension = extensions[0][1:] - } - } - } - - return saveAttachmentToStorage(ctx, b, orgID, msgUUID, mimeType, trace.ResponseBody, extension) -} - -func saveAttachmentToStorage(ctx context.Context, b *backend, orgID OrgID, msgUUID courier.MsgUUID, contentType string, data []byte, extension string) (string, error) { - // create our filename - filename := msgUUID.String() - if extension != "" { - filename = fmt.Sprintf("%s.%s", msgUUID, extension) - } - - path := filepath.Join(b.config.S3AttachmentsPrefix, strconv.FormatInt(int64(orgID), 10), filename[:4], filename[4:8], filename) - if !strings.HasPrefix(path, "/") { - path = fmt.Sprintf("/%s", path) - } - - start := time.Now() - s3URL, err := b.storage.Put(ctx, path, contentType, data) - if err != nil { - return "", errors.Wrapf(err, "error saving attachment to storage (bytes=%d, time=%dms)", len(data), time.Since(start)/time.Millisecond) - } - - // return our new media URL, which is prefixed by our content type - return fmt.Sprintf("%s:%s", contentType, s3URL), nil -} - //----------------------------------------------------------------------------- // Msg flusher for flushing failed writes //----------------------------------------------------------------------------- diff --git a/channel_log.go b/channel_log.go index 83ba19436..6399ccabd 100644 --- a/channel_log.go +++ b/channel_log.go @@ -18,13 +18,14 @@ type ChannelLogUUID uuids.UUID type ChannelLogType string const ( - ChannelLogTypeUnknown ChannelLogType = "unknown" - ChannelLogTypeMsgSend ChannelLogType = "msg_send" - ChannelLogTypeMsgStatus ChannelLogType = "msg_status" - ChannelLogTypeMsgReceive ChannelLogType = "msg_receive" - ChannelLogTypeEventReceive ChannelLogType = "event_receive" - ChannelLogTypeTokenFetch ChannelLogType = "token_fetch" - ChannelLogTypePageSubscribe ChannelLogType = "page_subscribe" + ChannelLogTypeUnknown ChannelLogType = "unknown" + ChannelLogTypeMsgSend ChannelLogType = "msg_send" + ChannelLogTypeMsgStatus ChannelLogType = "msg_status" + ChannelLogTypeMsgReceive ChannelLogType = "msg_receive" + ChannelLogTypeEventReceive ChannelLogType = "event_receive" + ChannelLogTypeAttachmentFetch ChannelLogType = "attachment_fetch" + ChannelLogTypeTokenRefresh ChannelLogType = "token_refresh" + ChannelLogTypePageSubscribe ChannelLogType = "page_subscribe" ) type ChannelError struct { @@ -105,6 +106,11 @@ func NewChannelLogForSend(msg Msg, redactVals []string) *ChannelLog { return newChannelLog(ChannelLogTypeMsgSend, msg.Channel(), nil, msg.ID(), redactVals) } +// NewChannelLogForSend creates a new channel log for an attachment fetch +func NewChannelLogForAttachmentFetch(ch Channel, redactVals []string) *ChannelLog { + return newChannelLog(ChannelLogTypeAttachmentFetch, ch, nil, NilMsgID, redactVals) +} + // NewChannelLog creates a new channel log with the given type and channel func NewChannelLog(t ChannelLogType, ch Channel, redactVals []string) *ChannelLog { return newChannelLog(t, ch, nil, NilMsgID, redactVals) diff --git a/channel_log_test.go b/channel_log_test.go index b3289bb3e..3746c9837 100644 --- a/channel_log_test.go +++ b/channel_log_test.go @@ -26,7 +26,7 @@ func TestChannelLog(t *testing.T) { defer uuids.SetGenerator(uuids.DefaultGenerator) channel := test.NewMockChannel("fef91e9b-a6ed-44fb-b6ce-feed8af585a8", "NX", "1234", "US", nil) - clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel, nil) + clog := courier.NewChannelLog(courier.ChannelLogTypeTokenRefresh, channel, nil) // make a request that will have a response req, _ := http.NewRequest("POST", "https://api.messages.com/send.json", nil) @@ -46,7 +46,7 @@ func TestChannelLog(t *testing.T) { clog.End() assert.Equal(t, courier.ChannelLogUUID("c00e5d67-c275-4389-aded-7d8b151cbd5b"), clog.UUID()) - assert.Equal(t, courier.ChannelLogTypeTokenFetch, clog.Type()) + assert.Equal(t, courier.ChannelLogTypeTokenRefresh, clog.Type()) assert.Equal(t, channel, clog.Channel()) assert.Equal(t, courier.NilMsgID, clog.MsgID()) assert.Equal(t, 2, len(clog.HTTPLogs())) diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 4edf4a93c..d664a8c00 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -169,7 +169,7 @@ type fetchPayload struct { // fetchAccessToken tries to fetch a new token for our channel, setting the result in redis func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) error { - clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel, h.RedactValues(channel)) + clog := courier.NewChannelLog(courier.ChannelLogTypeTokenRefresh, channel, h.RedactValues(channel)) tokenURL, _ := url.Parse(fmt.Sprintf("%s/%s", sendURL, "auth/token.action")) payload := &fetchPayload{ diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index 61b58bdb9..2b0adcbbc 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -98,7 +98,7 @@ func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http // fetchAccessToken tries to fetch a new token for our channel, setting the result in redis func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) error { - clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel, h.RedactValues(channel)) + clog := courier.NewChannelLog(courier.ChannelLogTypeTokenRefresh, channel, h.RedactValues(channel)) form := url.Values{ "grant_type": []string{"client_credential"}, diff --git a/server.go b/server.go index ab612e01e..15894000c 100644 --- a/server.go +++ b/server.go @@ -4,8 +4,9 @@ import ( "bytes" "compress/flate" "context" - "errors" + "encoding/json" "fmt" + "io" "log" "net/http" "os" @@ -20,6 +21,8 @@ import ( "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/analytics" "github.com/nyaruka/gocommon/httpx" + "github.com/nyaruka/gocommon/jsonx" + "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -107,6 +110,7 @@ func (s *server) Start() error { s.router.MethodNotAllowed(s.handle405) s.router.Get("/", s.handleIndex) s.router.Get("/status", s.handleStatus) + s.router.Get("/fetch-attachment", s.handleFetchAttachment) // initialize our handlers s.initializeChannelHandlers() @@ -421,6 +425,50 @@ func (s *server) handleStatus(w http.ResponseWriter, r *http.Request) { w.Write(buf.Bytes()) } +type fetchAttachmentRequest struct { + ChannelType ChannelType `json:"channel_type"` + ChannelUUID ChannelUUID `json:"channel_uuid"` + URL string `json:"url"` +} + +func (s *server) handleFetchAttachment(w http.ResponseWriter, r *http.Request) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute*1) + defer cancel() + + newURL, err := s.fetchAttachment(ctx, r) + if err != nil { + logrus.WithError(err).Error() + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(`Bad Request`)) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(jsonx.MustMarshal(map[string]any{"url": newURL})) +} + +func (s *server) fetchAttachment(ctx context.Context, r *http.Request) (string, error) { + body, err := io.ReadAll(r.Body) + if err != nil { + return "", errors.Wrap(err, "error reading request body") + } + + fa := &fetchAttachmentRequest{} + if err := json.Unmarshal(body, fa); err != nil { + return "", errors.Wrap(err, "error unmarshalling request") + } + + ch, err := s.backend.GetChannel(ctx, fa.ChannelType, fa.ChannelUUID) + if err != nil { + return "", errors.Wrap(err, "error getting channel") + } + + clog := NewChannelLogForAttachmentFetch(ch, GetHandler(ch.ChannelType()).RedactValues(ch)) + + return FetchAndStoreAttachment(ctx, s.backend, ch, fa.URL, clog) +} + // for use in request.Context type contextKey int diff --git a/test/backend.go b/test/backend.go index 99f147dbb..86115a7fc 100644 --- a/test/backend.go +++ b/test/backend.go @@ -328,6 +328,11 @@ func (mb *MockBackend) WriteExternalIDSeen(msg courier.Msg) { mb.seenExternalIDs = append(mb.seenExternalIDs, msg.ExternalID()) } +// SaveAttachment saves an attachment to backend storage +func (mb *MockBackend) SaveAttachment(ctx context.Context, ch courier.Channel, contentType string, data []byte, extension string) (string, error) { + return "", nil +} + // ResolveMedia resolves the passed in media URL to a media object func (mb *MockBackend) ResolveMedia(ctx context.Context, mediaUrl string) (courier.Media, error) { media := mb.media[mediaUrl] From 368183736c8e999dd8afffa866e1cdfc828871db Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 4 Oct 2022 11:25:43 -0500 Subject: [PATCH 215/294] Reorganize mocked handler test code --- handler_test.go | 99 ++++++------------------------------------------- test/handler.go | 85 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 88 deletions(-) create mode 100644 test/handler.go diff --git a/handler_test.go b/handler_test.go index caa93b35f..d6cf5541b 100644 --- a/handler_test.go +++ b/handler_test.go @@ -1,8 +1,6 @@ package courier_test import ( - "context" - "errors" "io" "net/http" "testing" @@ -11,86 +9,11 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/httpx" - "github.com/nyaruka/gocommon/urns" "github.com/stretchr/testify/assert" ) func init() { - courier.RegisterHandler(NewHandler()) -} - -type dummyHandler struct { - server courier.Server - backend courier.Backend -} - -// NewHandler returns a new Dummy handler -func NewHandler() courier.ChannelHandler { - return &dummyHandler{} -} - -func (h *dummyHandler) Server() courier.Server { return h.server } -func (h *dummyHandler) ChannelName() string { return "Dummy Handler" } -func (h *dummyHandler) ChannelType() courier.ChannelType { return courier.ChannelType("DM") } -func (h *dummyHandler) UseChannelRouteUUID() bool { return true } -func (h *dummyHandler) RedactValues(courier.Channel) []string { return []string{"sesame"} } - -func (h *dummyHandler) GetChannel(ctx context.Context, r *http.Request) (courier.Channel, error) { - dmChannel := test.NewMockChannel("e4bb1578-29da-4fa5-a214-9da19dd24230", "DM", "2020", "US", map[string]interface{}{}) - return dmChannel, nil -} - -// Initialize is called by the engine once everything is loaded -func (h *dummyHandler) Initialize(s courier.Server) error { - h.server = s - h.backend = s.Backend() - s.AddHandlerRoute(h, http.MethodGet, "receive", h.receiveMsg) - return nil -} - -// Send sends the given message, logging any HTTP calls or errors -func (h *dummyHandler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { - // log a request that contains a header value that should be redacted - req, _ := httpx.NewRequest("GET", "http://dummy.com/send", nil, map[string]string{"Authorization": "Token sesame"}) - trace, _ := httpx.DoTrace(http.DefaultClient, req, nil, nil, 1024) - clog.HTTP(trace) - - // log an error than contains a value that should be redacted - clog.RawError(errors.New("contains sesame seeds")) - - return h.backend.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgSent, clog), nil -} - -func (h *dummyHandler) WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, statuses []courier.MsgStatus) error { - return courier.WriteStatusSuccess(ctx, w, statuses) -} - -func (h *dummyHandler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { - return courier.WriteMsgSuccess(ctx, w, msgs) -} - -func (h *dummyHandler) WriteRequestError(ctx context.Context, w http.ResponseWriter, err error) error { - return courier.WriteError(ctx, w, http.StatusBadRequest, err) -} - -func (h *dummyHandler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter, details string) error { - return courier.WriteIgnored(ctx, w, details) -} - -// ReceiveMsg sends the passed in message, returning any error -func (h *dummyHandler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { - r.ParseForm() - from := r.Form.Get("from") - text := r.Form.Get("text") - if from == "" || text == "" { - return nil, errors.New("missing from or text") - } - - msg := h.backend.NewIncomingMsg(channel, urns.URN("tel:"+from), text, clog) - w.WriteHeader(200) - w.Write([]byte("ok")) - h.backend.WriteMsg(ctx, msg, clog) - return []courier.Event{msg}, nil + courier.RegisterHandler(test.NewMockHandler()) } func testConfig() *courier.Config { @@ -103,7 +26,7 @@ func testConfig() *courier.Config { func TestHandling(t *testing.T) { defer httpx.SetRequestor(httpx.DefaultRequestor) httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ - "http://dummy.com/send": { + "http://mock.com/send": { httpx.NewMockResponse(200, nil, []byte(`SENT`)), }, })) @@ -121,11 +44,11 @@ func TestHandling(t *testing.T) { time.Sleep(100 * time.Millisecond) // create and add a new outgoing message - xxChannel := test.NewMockChannel("53e5aafa-8155-449d-9009-fcb30d54bd26", "XX", "2020", "US", map[string]interface{}{}) - dmChannel := test.NewMockChannel("e4bb1578-29da-4fa5-a214-9da19dd24230", "DM", "2020", "US", map[string]interface{}{}) - mb.AddChannel(dmChannel) + brokenChannel := test.NewMockChannel("53e5aafa-8155-449d-9009-fcb30d54bd26", "XX", "2020", "US", map[string]interface{}{}) + mockChannel := test.NewMockChannel("e4bb1578-29da-4fa5-a214-9da19dd24230", "MCK", "2020", "US", map[string]interface{}{}) + mb.AddChannel(mockChannel) - msg := test.NewMockMsg(courier.NewMsgID(101), courier.NilMsgUUID, xxChannel, "tel:+250788383383", "test message") + msg := test.NewMockMsg(courier.NewMsgID(101), courier.NilMsgUUID, brokenChannel, "tel:+250788383383", "test message") mb.PushOutgoingMsg(msg) // sleep a second, sender should take care of it in that time @@ -140,7 +63,7 @@ func TestHandling(t *testing.T) { mb.Reset() // change our channel to our dummy channel - msg = test.NewMockMsg(courier.NewMsgID(102), courier.NilMsgUUID, dmChannel, "tel:+250788383383", "test message 2") + msg = test.NewMockMsg(courier.NewMsgID(102), courier.NilMsgUUID, mockChannel, "tel:+250788383383", "test message 2") // send it mb.PushOutgoingMsg(msg) @@ -159,8 +82,8 @@ func TestHandling(t *testing.T) { assert.Len(clog.HTTPLogs(), 1) hlog := clog.HTTPLogs()[0] - assert.Equal("http://dummy.com/send", hlog.URL) - assert.Equal("GET /send HTTP/1.1\r\nHost: dummy.com\r\nUser-Agent: Go-http-client/1.1\r\nAuthorization: Token **********\r\nAccept-Encoding: gzip\r\n\r\n", hlog.Request) + assert.Equal("http://mock.com/send", hlog.URL) + assert.Equal("GET /send HTTP/1.1\r\nHost: mock.com\r\nUser-Agent: Go-http-client/1.1\r\nAuthorization: Token **********\r\nAccept-Encoding: gzip\r\n\r\n", hlog.Request) mb.Reset() @@ -174,14 +97,14 @@ func TestHandling(t *testing.T) { assert.Equal(courier.MsgWired, mb.WrittenMsgStatuses()[0].Status()) // try to receive a message instead - resp, err := http.Get("http://localhost:8080/c/dm/e4bb1578-29da-4fa5-a214-9da19dd24230/receive") + resp, err := http.Get("http://localhost:8080/c/mck/e4bb1578-29da-4fa5-a214-9da19dd24230/receive") assert.NoError(err) assert.Equal(400, resp.StatusCode) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) assert.Contains(string(body), "missing from or text") - req, _ := http.NewRequest("GET", "http://localhost:8080/c/dm/e4bb1578-29da-4fa5-a214-9da19dd24230/receive?from=2065551212&text=hello", nil) + req, _ := http.NewRequest("GET", "http://localhost:8080/c/mck/e4bb1578-29da-4fa5-a214-9da19dd24230/receive?from=2065551212&text=hello", nil) req.Header.Set("Cookie", "secret") resp, err = http.DefaultClient.Do(req) assert.NoError(err) diff --git a/test/handler.go b/test/handler.go new file mode 100644 index 000000000..e98c7891e --- /dev/null +++ b/test/handler.go @@ -0,0 +1,85 @@ +package test + +import ( + "context" + "net/http" + + "github.com/nyaruka/courier" + "github.com/nyaruka/gocommon/httpx" + "github.com/nyaruka/gocommon/urns" + "github.com/pkg/errors" +) + +type mockHandler struct { + server courier.Server + backend courier.Backend +} + +// NewMockHandler returns a new mock handler +func NewMockHandler() courier.ChannelHandler { + return &mockHandler{} +} + +func (h *mockHandler) Server() courier.Server { return h.server } +func (h *mockHandler) ChannelName() string { return "Mock Handler" } +func (h *mockHandler) ChannelType() courier.ChannelType { return courier.ChannelType("MCK") } +func (h *mockHandler) UseChannelRouteUUID() bool { return true } +func (h *mockHandler) RedactValues(courier.Channel) []string { return []string{"sesame"} } + +func (h *mockHandler) GetChannel(ctx context.Context, r *http.Request) (courier.Channel, error) { + dmChannel := NewMockChannel("e4bb1578-29da-4fa5-a214-9da19dd24230", "MCK", "2020", "US", map[string]interface{}{}) + return dmChannel, nil +} + +// Initialize is called by the engine once everything is loaded +func (h *mockHandler) Initialize(s courier.Server) error { + h.server = s + h.backend = s.Backend() + s.AddHandlerRoute(h, http.MethodGet, "receive", h.receiveMsg) + return nil +} + +// Send sends the given message, logging any HTTP calls or errors +func (h *mockHandler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { + // log a request that contains a header value that should be redacted + req, _ := httpx.NewRequest("GET", "http://mock.com/send", nil, map[string]string{"Authorization": "Token sesame"}) + trace, _ := httpx.DoTrace(http.DefaultClient, req, nil, nil, 1024) + clog.HTTP(trace) + + // log an error than contains a value that should be redacted + clog.RawError(errors.New("contains sesame seeds")) + + return h.backend.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgSent, clog), nil +} + +func (h *mockHandler) WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, statuses []courier.MsgStatus) error { + return courier.WriteStatusSuccess(ctx, w, statuses) +} + +func (h *mockHandler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { + return courier.WriteMsgSuccess(ctx, w, msgs) +} + +func (h *mockHandler) WriteRequestError(ctx context.Context, w http.ResponseWriter, err error) error { + return courier.WriteError(ctx, w, http.StatusBadRequest, err) +} + +func (h *mockHandler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter, details string) error { + return courier.WriteIgnored(ctx, w, details) +} + +// ReceiveMsg sends the passed in message, returning any error +func (h *mockHandler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { + r.ParseForm() + from := r.Form.Get("from") + text := r.Form.Get("text") + if from == "" || text == "" { + return nil, errors.New("missing from or text") + } + + msg := h.backend.NewIncomingMsg(channel, urns.URN("tel:"+from), text, clog) + w.WriteHeader(200) + w.Write([]byte("ok")) + h.backend.WriteMsg(ctx, msg, clog) + return []courier.Event{msg}, nil +} From b0a64301c3c8467c59588bb61f74839703e600aa Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 4 Oct 2022 11:56:10 -0500 Subject: [PATCH 216/294] Fix channel log type token_refresh --- backends/rapidpro/backend_test.go | 2 +- channel_log.go | 2 +- channel_log_test.go | 4 ++-- handlers/jiochat/jiochat.go | 2 +- handlers/wechat/wechat.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 673a490d5..83f0e534b 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -1001,7 +1001,7 @@ func (ts *BackendTestSuite) TestWriteChanneLog() { trace, err := httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) ts.NoError(err) - clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel, nil) + clog := courier.NewChannelLog(courier.ChannelLogTypeTokenRefresh, channel, nil) clog.HTTP(trace) clog.RawError(errors.New("this is an error")) diff --git a/channel_log.go b/channel_log.go index 83ba19436..84477c0fd 100644 --- a/channel_log.go +++ b/channel_log.go @@ -23,7 +23,7 @@ const ( ChannelLogTypeMsgStatus ChannelLogType = "msg_status" ChannelLogTypeMsgReceive ChannelLogType = "msg_receive" ChannelLogTypeEventReceive ChannelLogType = "event_receive" - ChannelLogTypeTokenFetch ChannelLogType = "token_fetch" + ChannelLogTypeTokenRefresh ChannelLogType = "token_refresh" ChannelLogTypePageSubscribe ChannelLogType = "page_subscribe" ) diff --git a/channel_log_test.go b/channel_log_test.go index b3289bb3e..3746c9837 100644 --- a/channel_log_test.go +++ b/channel_log_test.go @@ -26,7 +26,7 @@ func TestChannelLog(t *testing.T) { defer uuids.SetGenerator(uuids.DefaultGenerator) channel := test.NewMockChannel("fef91e9b-a6ed-44fb-b6ce-feed8af585a8", "NX", "1234", "US", nil) - clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel, nil) + clog := courier.NewChannelLog(courier.ChannelLogTypeTokenRefresh, channel, nil) // make a request that will have a response req, _ := http.NewRequest("POST", "https://api.messages.com/send.json", nil) @@ -46,7 +46,7 @@ func TestChannelLog(t *testing.T) { clog.End() assert.Equal(t, courier.ChannelLogUUID("c00e5d67-c275-4389-aded-7d8b151cbd5b"), clog.UUID()) - assert.Equal(t, courier.ChannelLogTypeTokenFetch, clog.Type()) + assert.Equal(t, courier.ChannelLogTypeTokenRefresh, clog.Type()) assert.Equal(t, channel, clog.Channel()) assert.Equal(t, courier.NilMsgID, clog.MsgID()) assert.Equal(t, 2, len(clog.HTTPLogs())) diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 4edf4a93c..d664a8c00 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -169,7 +169,7 @@ type fetchPayload struct { // fetchAccessToken tries to fetch a new token for our channel, setting the result in redis func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) error { - clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel, h.RedactValues(channel)) + clog := courier.NewChannelLog(courier.ChannelLogTypeTokenRefresh, channel, h.RedactValues(channel)) tokenURL, _ := url.Parse(fmt.Sprintf("%s/%s", sendURL, "auth/token.action")) payload := &fetchPayload{ diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index 61b58bdb9..2b0adcbbc 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -98,7 +98,7 @@ func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http // fetchAccessToken tries to fetch a new token for our channel, setting the result in redis func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) error { - clog := courier.NewChannelLog(courier.ChannelLogTypeTokenFetch, channel, h.RedactValues(channel)) + clog := courier.NewChannelLog(courier.ChannelLogTypeTokenRefresh, channel, h.RedactValues(channel)) form := url.Values{ "grant_type": []string{"client_credential"}, From 132095c8ba4002836435e9cb866641d8fbc7e96b Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 4 Oct 2022 12:47:52 -0500 Subject: [PATCH 217/294] Add test for storing attachments --- attachments_test.go | 36 ++++++++++++++++++++++++++++-- handler_test.go | 4 ---- server.go | 8 ++++++- test/backend.go | 54 ++++++++++++++++++++++++++++++--------------- test/handler.go | 4 ++++ 5 files changed, 81 insertions(+), 25 deletions(-) diff --git a/attachments_test.go b/attachments_test.go index 0bee4495f..58c8caf16 100644 --- a/attachments_test.go +++ b/attachments_test.go @@ -1,7 +1,39 @@ package courier_test -import "testing" +import ( + "context" + "testing" + + "github.com/nyaruka/courier" + "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" + "github.com/stretchr/testify/assert" +) func TestFetchAndStoreAttachment(t *testing.T) { - // TODO + testJPG := test.ReadFile("test/testdata/test.jpg") + + defer httpx.SetRequestor(httpx.DefaultRequestor) + httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ + "http://mock.com/media/hello.jpg": { + httpx.NewMockResponse(200, nil, testJPG), + }, + })) + + ctx := context.Background() + mb := test.NewMockBackend() + + mockChannel := test.NewMockChannel("e4bb1578-29da-4fa5-a214-9da19dd24230", "MCK", "2020", "US", map[string]interface{}{}) + mb.AddChannel(mockChannel) + + clog := courier.NewChannelLogForAttachmentFetch(mockChannel, []string{"sesame"}) + + newURL, err := courier.FetchAndStoreAttachment(ctx, mb, mockChannel, "http://mock.com/media/hello.jpg", clog) + assert.NoError(t, err) + assert.Equal(t, "https://backend.com/attachments/test.jpg", newURL) + + assert.Len(t, mb.SavedAttachments(), 1) + assert.Equal(t, &test.SavedAttachment{Channel: mockChannel, ContentType: "image/jpeg", Data: testJPG, Extension: "jpg"}, mb.SavedAttachments()[0]) + assert.Len(t, clog.HTTPLogs(), 1) + assert.Equal(t, "http://mock.com/media/hello.jpg", clog.HTTPLogs()[0].URL) } diff --git a/handler_test.go b/handler_test.go index d6cf5541b..395a4bd0e 100644 --- a/handler_test.go +++ b/handler_test.go @@ -12,10 +12,6 @@ import ( "github.com/stretchr/testify/assert" ) -func init() { - courier.RegisterHandler(test.NewMockHandler()) -} - func testConfig() *courier.Config { config := courier.NewConfig() config.DB = "postgres://courier:courier@localhost:5432/courier_test?sslmode=disable" diff --git a/server.go b/server.go index 15894000c..efc54e017 100644 --- a/server.go +++ b/server.go @@ -466,7 +466,13 @@ func (s *server) fetchAttachment(ctx context.Context, r *http.Request) (string, clog := NewChannelLogForAttachmentFetch(ch, GetHandler(ch.ChannelType()).RedactValues(ch)) - return FetchAndStoreAttachment(ctx, s.backend, ch, fa.URL, clog) + newURL, err := FetchAndStoreAttachment(ctx, s.backend, ch, fa.URL, clog) + + if err := s.backend.WriteChannelLog(ctx, clog); err != nil { + logrus.WithError(err).Error() + } + + return newURL, err } // for use in request.Context diff --git a/test/backend.go b/test/backend.go index 86115a7fc..193252c4e 100644 --- a/test/backend.go +++ b/test/backend.go @@ -2,6 +2,7 @@ package test import ( "context" + "fmt" "log" "sync" "time" @@ -18,6 +19,17 @@ func init() { courier.RegisterBackend("mock", buildMockBackend) } +func buildMockBackend(config *courier.Config) courier.Backend { + return NewMockBackend() +} + +type SavedAttachment struct { + Channel courier.Channel + ContentType string + Data []byte + Extension string +} + // MockBackend is a mocked version of a backend which doesn't require a real database or cache type MockBackend struct { channels map[courier.ChannelUUID]courier.Channel @@ -34,6 +46,7 @@ type MockBackend struct { writtenMsgStatuses []courier.MsgStatus writtenChannelEvents []courier.ChannelEvent writtenChannelLogs []*courier.ChannelLog + savedAttachments []*SavedAttachment lastMsgID courier.MsgID lastContactName string @@ -75,21 +88,6 @@ func NewMockBackend() *MockBackend { } } -func (mb *MockBackend) WrittenMsgs() []courier.Msg { return mb.writtenMsgs } -func (mb *MockBackend) WrittenMsgStatuses() []courier.MsgStatus { return mb.writtenMsgStatuses } -func (mb *MockBackend) WrittenChannelEvents() []courier.ChannelEvent { return mb.writtenChannelEvents } -func (mb *MockBackend) WrittenChannelLogs() []*courier.ChannelLog { return mb.writtenChannelLogs } - -// LastContactName returns the contact name set on the last msg or channel event written -func (mb *MockBackend) LastContactName() string { - return mb.lastContactName -} - -// MockMedia adds the given media to the mocked backend -func (mb *MockBackend) MockMedia(media courier.Media) { - mb.media[media.URL()] = media -} - // DeleteMsgWithExternalID delete a message we receive an event that it should be deleted func (mb *MockBackend) DeleteMsgWithExternalID(ctx context.Context, channel courier.Channel, externalID string) error { return nil @@ -330,7 +328,11 @@ func (mb *MockBackend) WriteExternalIDSeen(msg courier.Msg) { // SaveAttachment saves an attachment to backend storage func (mb *MockBackend) SaveAttachment(ctx context.Context, ch courier.Channel, contentType string, data []byte, extension string) (string, error) { - return "", nil + mb.savedAttachments = append(mb.savedAttachments, &SavedAttachment{ + Channel: ch, ContentType: contentType, Data: data, Extension: extension, + }) + + return fmt.Sprintf("https://backend.com/attachments/test.%s", extension), nil } // ResolveMedia resolves the passed in media URL to a media object @@ -363,6 +365,22 @@ func (mb *MockBackend) RedisPool() *redis.Pool { return mb.redisPool } -func buildMockBackend(config *courier.Config) courier.Backend { - return NewMockBackend() +//////////////////////////////////////////////////////////////////////////////// +// Methods not part of the backed interface but used in tests +//////////////////////////////////////////////////////////////////////////////// + +func (mb *MockBackend) WrittenMsgs() []courier.Msg { return mb.writtenMsgs } +func (mb *MockBackend) WrittenMsgStatuses() []courier.MsgStatus { return mb.writtenMsgStatuses } +func (mb *MockBackend) WrittenChannelEvents() []courier.ChannelEvent { return mb.writtenChannelEvents } +func (mb *MockBackend) WrittenChannelLogs() []*courier.ChannelLog { return mb.writtenChannelLogs } +func (mb *MockBackend) SavedAttachments() []*SavedAttachment { return mb.savedAttachments } + +// LastContactName returns the contact name set on the last msg or channel event written +func (mb *MockBackend) LastContactName() string { + return mb.lastContactName +} + +// MockMedia adds the given media to the mocked backend +func (mb *MockBackend) MockMedia(media courier.Media) { + mb.media[media.URL()] = media } diff --git a/test/handler.go b/test/handler.go index e98c7891e..8f4b21b74 100644 --- a/test/handler.go +++ b/test/handler.go @@ -10,6 +10,10 @@ import ( "github.com/pkg/errors" ) +func init() { + courier.RegisterHandler(NewMockHandler()) +} + type mockHandler struct { server courier.Server backend courier.Backend From d721f2553c17b15642ced2c766e22897d37ef140 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 5 Oct 2022 17:40:22 +0200 Subject: [PATCH 218/294] Skip SSL verification for AC channels --- handlers/arabiacell/arabiacell.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/arabiacell/arabiacell.go b/handlers/arabiacell/arabiacell.go index 2ed0c2bdc..8b9cdcc34 100644 --- a/handlers/arabiacell/arabiacell.go +++ b/handlers/arabiacell/arabiacell.go @@ -96,7 +96,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/xml") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := handlers.RequestHTTPInsecure(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } From 35e3e74791581a77f349af2b8a9c27a316f707ca Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 5 Oct 2022 12:08:05 -0500 Subject: [PATCH 219/294] Return log UUID, size and add tests (WIP) --- attachments.go | 11 +++--- attachments_test.go | 9 ++++- backends/rapidpro/msg.go | 2 +- handlers/facebookapp/facebookapp.go | 2 +- handlers/forms.go | 16 +++----- handlers/whatsapp/whatsapp.go | 2 +- server.go | 34 ++++++++++------- server_test.go | 57 +++++++++++++++++++++++++++++ test/backend.go | 48 ++++++++++++------------ utils/misc.go | 10 +++++ 10 files changed, 132 insertions(+), 59 deletions(-) diff --git a/attachments.go b/attachments.go index 3e7974ce4..8e763dd22 100644 --- a/attachments.go +++ b/attachments.go @@ -17,10 +17,10 @@ const ( maxAttBodyReadBytes = 100 * 1024 * 1024 ) -func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, attURL string, clog *ChannelLog) (string, error) { +func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, attURL string, clog *ChannelLog) (string, int, error) { parsedURL, err := url.Parse(attURL) if err != nil { - return "", err + return "", 0, err } var httpClient *http.Client @@ -37,7 +37,7 @@ func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, at } if err != nil { - return "", errors.Wrap(err, "unable to create attachment request") + return "", 0, errors.Wrap(err, "unable to create attachment request") } trace, err := httpx.DoTrace(httpClient, attRequest, nil, nil, maxAttBodyReadBytes) @@ -45,7 +45,7 @@ func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, at clog.HTTP(trace) } if err != nil { - return "", err + return "", 0, err } mimeType := "" @@ -81,5 +81,6 @@ func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, at } } - return b.SaveAttachment(ctx, channel, mimeType, trace.ResponseBody, extension) + newURL, err := b.SaveAttachment(ctx, channel, mimeType, trace.ResponseBody, extension) + return newURL, len(trace.ResponseBody), err } diff --git a/attachments_test.go b/attachments_test.go index 58c8caf16..2d2c61132 100644 --- a/attachments_test.go +++ b/attachments_test.go @@ -7,6 +7,7 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/httpx" + "github.com/nyaruka/gocommon/uuids" "github.com/stretchr/testify/assert" ) @@ -20,6 +21,9 @@ func TestFetchAndStoreAttachment(t *testing.T) { }, })) + defer uuids.SetGenerator(uuids.DefaultGenerator) + uuids.SetGenerator(uuids.NewSeededGenerator(1234)) + ctx := context.Background() mb := test.NewMockBackend() @@ -28,9 +32,10 @@ func TestFetchAndStoreAttachment(t *testing.T) { clog := courier.NewChannelLogForAttachmentFetch(mockChannel, []string{"sesame"}) - newURL, err := courier.FetchAndStoreAttachment(ctx, mb, mockChannel, "http://mock.com/media/hello.jpg", clog) + newURL, size, err := courier.FetchAndStoreAttachment(ctx, mb, mockChannel, "http://mock.com/media/hello.jpg", clog) assert.NoError(t, err) - assert.Equal(t, "https://backend.com/attachments/test.jpg", newURL) + assert.Equal(t, "https://backend.com/attachments/cdf7ed27-5ad5-4028-b664-880fc7581c77.jpg", newURL) + assert.Equal(t, 17301, size) assert.Len(t, mb.SavedAttachments(), 1) assert.Equal(t, &test.SavedAttachment{Channel: mockChannel, ContentType: "image/jpeg", Data: testJPG, Extension: "jpg"}, mb.SavedAttachments()[0]) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index 730f229bc..41f8f5513 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -59,7 +59,7 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch var err error if strings.HasPrefix(attURL, "http://") || strings.HasPrefix(attURL, "https://") { - newURL, err = courier.FetchAndStoreAttachment(ctx, b, channel, attURL, clog) + newURL, _, err = courier.FetchAndStoreAttachment(ctx, b, channel, attURL, clog) if err != nil { return err } diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index f58ddf7f9..d0098757f 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -1424,7 +1424,7 @@ func (h *handler) getTemplate(msg courier.Msg) (*MsgTemplating, error) { } // check our template is valid - err = handlers.Validate(templating) + err = utils.Validate(templating) if err != nil { return nil, errors.Wrapf(err, "invalid templating definition") } diff --git a/handlers/forms.go b/handlers/forms.go index aeee24900..31eb37831 100644 --- a/handlers/forms.go +++ b/handlers/forms.go @@ -9,12 +9,11 @@ import ( "net/http" "github.com/gorilla/schema" - validator "gopkg.in/go-playground/validator.v9" + "github.com/nyaruka/courier/utils" ) var ( - decoder = schema.NewDecoder() - validate = validator.New() + decoder = schema.NewDecoder() ) func init() { @@ -22,11 +21,6 @@ func init() { decoder.SetAliasTag("name") } -// Validate validates the passe din struct using our shared validator instance -func Validate(form interface{}) error { - return validate.Struct(form) -} - // DecodeAndValidateForm takes the passed in form and attempts to parse and validate it from the // URL query parameters as well as any POST parameters of the passed in request func DecodeAndValidateForm(form interface{}, r *http.Request) error { @@ -41,7 +35,7 @@ func DecodeAndValidateForm(form interface{}, r *http.Request) error { } // check our input is valid - err = validate.Struct(form) + err = utils.Validate(form) if err != nil { return err } @@ -63,7 +57,7 @@ func DecodeAndValidateJSON(envelope interface{}, r *http.Request) error { } // check our input is valid - err = validate.Struct(envelope) + err = utils.Validate(envelope) if err != nil { return fmt.Errorf("request JSON doesn't match required schema: %s", err) } @@ -85,7 +79,7 @@ func DecodeAndValidateXML(envelope interface{}, r *http.Request) error { } // check our input is valid - err = validate.Struct(envelope) + err = utils.Validate(envelope) if err != nil { return fmt.Errorf("request XML doesn't match required schema: %s", err) } diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index 44995f75a..65a90104c 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -1148,7 +1148,7 @@ func (h *handler) getTemplate(msg courier.Msg) (*MsgTemplating, error) { } // check our template is valid - err = handlers.Validate(templating) + err = utils.Validate(templating) if err != nil { return nil, errors.Wrapf(err, "invalid templating definition") } diff --git a/server.go b/server.go index efc54e017..31519c712 100644 --- a/server.go +++ b/server.go @@ -110,7 +110,7 @@ func (s *server) Start() error { s.router.MethodNotAllowed(s.handle405) s.router.Get("/", s.handleIndex) s.router.Get("/status", s.handleStatus) - s.router.Get("/fetch-attachment", s.handleFetchAttachment) + s.router.Post("/fetch-attachment", s.handleFetchAttachment) // initialize our handlers s.initializeChannelHandlers() @@ -426,53 +426,59 @@ func (s *server) handleStatus(w http.ResponseWriter, r *http.Request) { } type fetchAttachmentRequest struct { - ChannelType ChannelType `json:"channel_type"` - ChannelUUID ChannelUUID `json:"channel_uuid"` - URL string `json:"url"` + ChannelType ChannelType `json:"channel_type" validate:"required"` + ChannelUUID ChannelUUID `json:"channel_uuid" validate:"required,uuid"` + URL string `json:"url" validate:"required"` } func (s *server) handleFetchAttachment(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(context.Background(), time.Minute*1) defer cancel() - newURL, err := s.fetchAttachment(ctx, r) + newURL, size, clog, err := s.fetchAttachment(ctx, r) if err != nil { logrus.WithError(err).Error() - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(`Bad Request`)) + WriteError(ctx, w, http.StatusBadRequest, err) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - w.Write(jsonx.MustMarshal(map[string]any{"url": newURL})) + w.Write(jsonx.MustMarshal(map[string]any{ + "url": newURL, + "size": size, + "log_uuid": clog.UUID(), + })) } -func (s *server) fetchAttachment(ctx context.Context, r *http.Request) (string, error) { +func (s *server) fetchAttachment(ctx context.Context, r *http.Request) (string, int, *ChannelLog, error) { body, err := io.ReadAll(r.Body) if err != nil { - return "", errors.Wrap(err, "error reading request body") + return "", 0, nil, errors.Wrap(err, "error reading request body") } fa := &fetchAttachmentRequest{} if err := json.Unmarshal(body, fa); err != nil { - return "", errors.Wrap(err, "error unmarshalling request") + return "", 0, nil, errors.Wrap(err, "error unmarshalling request") + } + if err := utils.Validate(fa); err != nil { + return "", 0, nil, err } ch, err := s.backend.GetChannel(ctx, fa.ChannelType, fa.ChannelUUID) if err != nil { - return "", errors.Wrap(err, "error getting channel") + return "", 0, nil, errors.Wrap(err, "error getting channel") } clog := NewChannelLogForAttachmentFetch(ch, GetHandler(ch.ChannelType()).RedactValues(ch)) - newURL, err := FetchAndStoreAttachment(ctx, s.backend, ch, fa.URL, clog) + newURL, size, err := FetchAndStoreAttachment(ctx, s.backend, ch, fa.URL, clog) if err := s.backend.WriteChannelLog(ctx, clog); err != nil { logrus.WithError(err).Error() } - return newURL, err + return newURL, size, clog, err } // for use in request.Context diff --git a/server_test.go b/server_test.go index 41ad3083a..1d7eca2e1 100644 --- a/server_test.go +++ b/server_test.go @@ -1,15 +1,19 @@ package courier_test import ( + "fmt" "net/http" + "strings" "testing" "time" "github.com/nyaruka/courier" "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/httpx" + "github.com/nyaruka/gocommon/uuids" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestServer(t *testing.T) { @@ -56,3 +60,56 @@ func TestServer(t *testing.T) { assert.NoError(t, err) assert.Contains(t, string(trace.ResponseBody), "method not allowed") } + +func TestFetchAttachment(t *testing.T) { + testJPG := test.ReadFile("test/testdata/test.jpg") + + defer httpx.SetRequestor(httpx.DefaultRequestor) + httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ + "http://mock.com/media/hello.jpg": { + httpx.NewMockResponse(200, nil, testJPG), + }, + })) + + defer uuids.SetGenerator(uuids.DefaultGenerator) + uuids.SetGenerator(uuids.NewSeededGenerator(1234)) + + logger := logrus.New() + config := courier.NewConfig() + config.StatusUsername = "admin" + config.StatusPassword = "password123" + + mb := test.NewMockBackend() + mockChannel := test.NewMockChannel("e4bb1578-29da-4fa5-a214-9da19dd24230", "MCK", "2020", "US", map[string]interface{}{}) + mb.AddChannel(mockChannel) + + server := courier.NewServerWithLogger(config, mb, logger) + server.Start() + defer server.Stop() + + // wait for server to come up + time.Sleep(100 * time.Millisecond) + + submit := func(body string) (int, []byte) { + req, _ := http.NewRequest("POST", "http://localhost:8080/fetch-attachment", strings.NewReader(body)) + fmt.Println(req.Host) + fmt.Println(req.URL.Hostname()) + trace, err := httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) + require.NoError(t, err) + return trace.Response.StatusCode, trace.ResponseBody + } + + // try to submit with empty body + statusCode, respBody := submit(`{}`) + assert.Equal(t, 400, statusCode) + assert.Contains(t, string(respBody), `Field validation for 'ChannelType' failed on the 'required' tag`) + + // try to submit with non-existent channel + statusCode, respBody = submit(`{"channel_uuid": "c25aab53-f23a-46c9-8ae3-1af850ad9fd9", "channel_type": "VV", "url": "http://mock.com/media/test.jpg"}`) + assert.Equal(t, 400, statusCode) + assert.Contains(t, string(respBody), `channel not found`) + + statusCode, respBody = submit(`{"channel_uuid": "e4bb1578-29da-4fa5-a214-9da19dd24230", "channel_type": "MCK", "url": "http://mock.com/media/test.jpg"}`) + assert.Equal(t, 200, statusCode) + assert.JSONEq(t, `{"log_uuid":"c00e5d67-c275-4389-aded-7d8b151cbd5b", "size": 15238, "url": "https://backend.com/attachments/cdf7ed27-5ad5-4028-b664-880fc7581c77.jpg"}`, string(respBody)) +} diff --git a/test/backend.go b/test/backend.go index 193252c4e..55b6b9cfe 100644 --- a/test/backend.go +++ b/test/backend.go @@ -276,18 +276,6 @@ func (mb *MockBackend) RemoveURNfromContact(context context.Context, channel cou return urn, nil } -// AddChannel adds a test channel to the test server -func (mb *MockBackend) AddChannel(channel courier.Channel) { - mb.channels[channel.UUID()] = channel - mb.channelsByAddress[channel.ChannelAddress()] = channel -} - -// ClearChannels is a utility function on our mock server to clear all added channels -func (mb *MockBackend) ClearChannels() { - mb.channels = nil - mb.channelsByAddress = nil -} - // Start starts our mock backend func (mb *MockBackend) Start() error { return nil } @@ -297,17 +285,6 @@ func (mb *MockBackend) Stop() error { return nil } // Cleanup cleans up any connections that are open func (mb *MockBackend) Cleanup() error { return nil } -// Reset clears our queued messages, seen external IDs, and channel logs -func (mb *MockBackend) Reset() { - mb.lastMsgID = courier.NilMsgID - mb.seenExternalIDs = nil - - mb.writtenMsgs = nil - mb.writtenMsgStatuses = nil - mb.writtenChannelEvents = nil - mb.writtenChannelLogs = nil -} - // CheckExternalIDSeen checks if external ID has been seen in a period func (mb *MockBackend) CheckExternalIDSeen(msg courier.Msg) courier.Msg { m := msg.(*mockMsg) @@ -332,7 +309,7 @@ func (mb *MockBackend) SaveAttachment(ctx context.Context, ch courier.Channel, c Channel: ch, ContentType: contentType, Data: data, Extension: extension, }) - return fmt.Sprintf("https://backend.com/attachments/test.%s", extension), nil + return fmt.Sprintf("https://backend.com/attachments/%s.%s", uuids.New(), extension), nil } // ResolveMedia resolves the passed in media URL to a media object @@ -384,3 +361,26 @@ func (mb *MockBackend) LastContactName() string { func (mb *MockBackend) MockMedia(media courier.Media) { mb.media[media.URL()] = media } + +// AddChannel adds a test channel to the test server +func (mb *MockBackend) AddChannel(channel courier.Channel) { + mb.channels[channel.UUID()] = channel + mb.channelsByAddress[channel.ChannelAddress()] = channel +} + +// ClearChannels is a utility function on our mock server to clear all added channels +func (mb *MockBackend) ClearChannels() { + mb.channels = nil + mb.channelsByAddress = nil +} + +// Reset clears our queued messages, seen external IDs, and channel logs +func (mb *MockBackend) Reset() { + mb.lastMsgID = courier.NilMsgID + mb.seenExternalIDs = nil + + mb.writtenMsgs = nil + mb.writtenMsgStatuses = nil + mb.writtenChannelEvents = nil + mb.writtenChannelLogs = nil +} diff --git a/utils/misc.go b/utils/misc.go index 8f73b9a15..6a5ee38d0 100644 --- a/utils/misc.go +++ b/utils/misc.go @@ -10,8 +10,18 @@ import ( "regexp" "strings" "unicode/utf8" + + validator "gopkg.in/go-playground/validator.v9" +) + +var ( + validate = validator.New() ) +func Validate(obj any) error { + return validate.Struct(obj) +} + // SignHMAC256 encrypts value with HMAC256 by using a private key func SignHMAC256(privateKey string, value string) string { hash := hmac.New(sha256.New, []byte(privateKey)) From bb19225b85e4d9efc7c9ce01474d14bd88e5ed9b Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 5 Oct 2022 13:08:29 -0500 Subject: [PATCH 220/294] Update dependencies --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- handlers/whatsapp/whatsapp.go | 3 ++- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 95037cdb4..a2ced9847 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.6 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.30.1 + github.com/nyaruka/gocommon v1.31.0 github.com/nyaruka/null v1.2.0 github.com/nyaruka/redisx v0.2.2 github.com/patrickmn/go-cache v2.1.0+incompatible @@ -28,7 +28,7 @@ require ( require ( github.com/antchfx/xpath v1.2.1 // indirect - github.com/aws/aws-sdk-go v1.44.105 // indirect + github.com/aws/aws-sdk-go v1.44.111 // indirect github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/structs v1.1.0 // indirect @@ -48,8 +48,8 @@ require ( github.com/nyaruka/phonenumbers v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect - golang.org/x/net v0.0.0-20220923203811-8be639271d50 // indirect - golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25 // indirect + golang.org/x/net v0.0.0-20221004154528-8021a29435af // indirect + golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/go.sum b/go.sum index 65da91f8c..aee51a2d4 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/antchfx/xmlquery v1.3.12 h1:6TMGpdjpO/P8VhjnaYPXuqT3qyJ/VsqoyNTmJzNBT github.com/antchfx/xmlquery v1.3.12/go.mod h1:3w2RvQvTz+DaT5fSgsELkSJcdNgkmg6vuXDEuhdwsPQ= github.com/antchfx/xpath v1.2.1 h1:qhp4EW6aCOVr5XIkT+l6LJ9ck/JsUH/yyauNgTQkBF8= github.com/antchfx/xpath v1.2.1/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= -github.com/aws/aws-sdk-go v1.44.105 h1:UUwoD1PRKIj3ltrDUYTDQj5fOTK3XsnqolLpRTMmSEM= -github.com/aws/aws-sdk-go v1.44.105/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.111 h1:AcWfOgeedSQ4gQVwcIe6aLxpQNJMloZQyqnr7Dzki+s= +github.com/aws/aws-sdk-go v1.44.111/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s= @@ -77,8 +77,8 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.30.1 h1:W4n0GwTbcsI90vL7bpaCoGEtnc+fRn6FK/nTQtptrxw= -github.com/nyaruka/gocommon v1.30.1/go.mod h1:PApT/06fP5Tzs4/kbkJ+rVoyOc9Lbqm1lR0ow8Vqzp0= +github.com/nyaruka/gocommon v1.31.0 h1:eVRxmyTZxRQ4mBs3JoYaPe33LlNuQD63pxq2M+eHQA8= +github.com/nyaruka/gocommon v1.31.0/go.mod h1:PApT/06fP5Tzs4/kbkJ+rVoyOc9Lbqm1lR0ow8Vqzp0= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= @@ -115,15 +115,15 @@ golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220923203811-8be639271d50 h1:vKyz8L3zkd+xrMeIaBsQ/MNVPVFSffdaU3ZyYlBGFnI= -golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4= +golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25 h1:nwzwVf0l2Y/lkov/+IYgMMbFyI+QypZDds9RxlSmsFQ= -golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI= +golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index 44995f75a..88c66835c 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -901,7 +901,8 @@ func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string, clog return "", errors.Wrapf(err, "error building request to media endpoint") } setWhatsAppAuthHeader(&req.Header, msg.Channel()) - req.Header.Add("Content-Type", httpx.DetectContentType(respBody)) + mediaType, _ := httpx.DetectContentType(respBody) + req.Header.Add("Content-Type", mediaType) resp, respBody, err = handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { From 5604cfa942ba9d57a7616663fce3db1b590bc05e Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 5 Oct 2022 13:09:01 -0500 Subject: [PATCH 221/294] Update CHANGELOG.md for v7.5.43 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea563d73e..18fc91b89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +v7.5.43 +---------- + * Update dependencies + * Skip SSL verification for AC channels + * Fix channel log type token_refresh + v7.5.42 ---------- * Add channel UUID and type to queued msg events From 768d85d7847c567658e7a6613b122f802d93d655 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 5 Oct 2022 13:37:28 -0500 Subject: [PATCH 222/294] Fix tests --- backends/rapidpro/backend_test.go | 14 ++++++++++++++ server_test.go | 16 ++++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 83f0e534b..b13fa455f 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -26,6 +26,7 @@ import ( "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/storage" "github.com/nyaruka/gocommon/urns" + "github.com/nyaruka/gocommon/uuids" "github.com/nyaruka/null" "github.com/nyaruka/redisx/assertredis" "github.com/sirupsen/logrus" @@ -1100,7 +1101,20 @@ func (ts *BackendTestSuite) TestWriteAttachment() { ts.Equal(1, len(msg.Attachments())) ts.True(strings.HasPrefix(msg.Attachments()[0], "image/jpeg:")) ts.True(strings.HasSuffix(msg.Attachments()[0], ".jpg")) +} + +func (ts *BackendTestSuite) TestSaveAttachment() { + testJPG := test.ReadFile("../../test/testdata/test.jpg") + ctx := context.Background() + knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") + + defer uuids.SetGenerator(uuids.DefaultGenerator) + uuids.SetGenerator(uuids.NewSeededGenerator(1234)) + + newURL, err := ts.b.SaveAttachment(ctx, knChannel, "image/jpeg", testJPG, "jpg") + ts.NoError(err) + ts.Equal("image/jpeg:_test_storage/media/1/c00e/5d67/c00e5d67-c275-4389-aded-7d8b151cbd5b.jpg", newURL) } func (ts *BackendTestSuite) TestWriteMsg() { diff --git a/server_test.go b/server_test.go index 1d7eca2e1..546ce08ed 100644 --- a/server_test.go +++ b/server_test.go @@ -1,7 +1,6 @@ package courier_test import ( - "fmt" "net/http" "strings" "testing" @@ -64,12 +63,15 @@ func TestServer(t *testing.T) { func TestFetchAttachment(t *testing.T) { testJPG := test.ReadFile("test/testdata/test.jpg") - defer httpx.SetRequestor(httpx.DefaultRequestor) - httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ - "http://mock.com/media/hello.jpg": { + httpMocks := httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ + "http://mock.com/media/test.jpg": { httpx.NewMockResponse(200, nil, testJPG), }, - })) + }) + httpMocks.SetIgnoreLocal(true) + + defer httpx.SetRequestor(httpx.DefaultRequestor) + httpx.SetRequestor(httpMocks) defer uuids.SetGenerator(uuids.DefaultGenerator) uuids.SetGenerator(uuids.NewSeededGenerator(1234)) @@ -92,8 +94,6 @@ func TestFetchAttachment(t *testing.T) { submit := func(body string) (int, []byte) { req, _ := http.NewRequest("POST", "http://localhost:8080/fetch-attachment", strings.NewReader(body)) - fmt.Println(req.Host) - fmt.Println(req.URL.Hostname()) trace, err := httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) require.NoError(t, err) return trace.Response.StatusCode, trace.ResponseBody @@ -111,5 +111,5 @@ func TestFetchAttachment(t *testing.T) { statusCode, respBody = submit(`{"channel_uuid": "e4bb1578-29da-4fa5-a214-9da19dd24230", "channel_type": "MCK", "url": "http://mock.com/media/test.jpg"}`) assert.Equal(t, 200, statusCode) - assert.JSONEq(t, `{"log_uuid":"c00e5d67-c275-4389-aded-7d8b151cbd5b", "size": 15238, "url": "https://backend.com/attachments/cdf7ed27-5ad5-4028-b664-880fc7581c77.jpg"}`, string(respBody)) + assert.JSONEq(t, `{"log_uuid":"c00e5d67-c275-4389-aded-7d8b151cbd5b", "size": 17301, "url": "https://backend.com/attachments/cdf7ed27-5ad5-4028-b664-880fc7581c77.jpg"}`, string(respBody)) } From cb46ddf00dc5d7a807976933aeb9004a72073883 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 6 Oct 2022 09:20:24 -0500 Subject: [PATCH 223/294] Tweak server so that it's easier to add a new non-channel, public endpoint --- server.go | 26 +++++++++--------- server_test.go | 70 +++++++++++++++++++++++++++---------------------- test/backend.go | 2 +- 3 files changed, 53 insertions(+), 45 deletions(-) diff --git a/server.go b/server.go index ab612e01e..d28cade41 100644 --- a/server.go +++ b/server.go @@ -62,15 +62,15 @@ func NewServerWithLogger(config *Config, backend Backend, logger *logrus.Logger) router.Use(middleware.Recoverer) router.Use(middleware.Timeout(30 * time.Second)) - chanRouter := chi.NewRouter() - router.Mount("/c/", chanRouter) + publicRouter := chi.NewRouter() + router.Mount("/c/", publicRouter) return &server{ config: config, backend: backend, - router: router, - chanRouter: chanRouter, + router: router, + publicRouter: publicRouter, stopChan: make(chan bool), waitGroup: &sync.WaitGroup{}, @@ -215,9 +215,9 @@ func (s *server) Router() chi.Router { return s.router } type server struct { backend Backend - httpServer *http.Server - router *chi.Mux - chanRouter *chi.Mux + httpServer *http.Server + router *chi.Mux + publicRouter *chi.Mux foreman *Foreman @@ -227,7 +227,7 @@ type server struct { stopChan chan bool stopped bool - routes []string + chanRoutes []string // used for index page } func (s *server) initializeChannelHandlers() { @@ -249,7 +249,7 @@ func (s *server) initializeChannelHandlers() { } // sort our route help - sort.Strings(s.routes) + sort.Strings(s.chanRoutes) } func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc ChannelHandleFunc) http.HandlerFunc { @@ -361,8 +361,8 @@ func (s *server) AddHandlerRoute(handler ChannelHandler, method string, action s if action != "" { path = fmt.Sprintf("%s/%s", path, action) } - s.chanRouter.Method(method, path, s.channelHandleWrapper(handler, handlerFunc)) - s.routes = append(s.routes, fmt.Sprintf("%-20s - %s %s", "/c"+path, handler.ChannelName(), action)) + s.publicRouter.Method(method, path, s.channelHandleWrapper(handler, handlerFunc)) + s.chanRoutes = append(s.chanRoutes, fmt.Sprintf("%-20s - %s %s", "/c"+path, handler.ChannelName(), action)) } func (s *server) handleIndex(w http.ResponseWriter, r *http.Request) { @@ -375,7 +375,7 @@ func (s *server) handleIndex(w http.ResponseWriter, r *http.Request) { buf.WriteString(s.backend.Health()) buf.WriteString("\n\n") - buf.WriteString(strings.Join(s.routes, "\n")) + buf.WriteString(strings.Join(s.chanRoutes, "\n")) buf.WriteString("") w.Write(buf.Bytes()) } @@ -404,7 +404,7 @@ func (s *server) handleStatus(w http.ResponseWriter, r *http.Request) { if !ok || user != s.config.StatusUsername || pass != s.config.StatusPassword { w.Header().Set("WWW-Authenticate", `Basic realm="Authenticate"`) w.WriteHeader(401) - w.Write([]byte("Unauthorised.\n")) + w.Write([]byte("Unauthorized.\n")) return } } diff --git a/server_test.go b/server_test.go index 41ad3083a..e7659201c 100644 --- a/server_test.go +++ b/server_test.go @@ -10,6 +10,7 @@ import ( "github.com/nyaruka/gocommon/httpx" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestServer(t *testing.T) { @@ -18,41 +19,48 @@ func TestServer(t *testing.T) { config.StatusUsername = "admin" config.StatusPassword = "password123" - server := courier.NewServerWithLogger(config, test.NewMockBackend(), logger) + mb := test.NewMockBackend() + mb.AddChannel(test.NewMockChannel("95710b36-855d-4832-a723-5f71f73688a0", "MCK", "12345", "RW", nil)) + + server := courier.NewServerWithLogger(config, mb, logger) server.Start() defer server.Stop() // wait for server to come up time.Sleep(100 * time.Millisecond) - // hit our main pages, this is admitedly mostly in the name of coverage - req, _ := http.NewRequest("GET", "http://localhost:8080/", nil) - trace, err := httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) - assert.NoError(t, err) - assert.Contains(t, string(trace.ResponseBody), "courier") - - // status page without auth - req, _ = http.NewRequest("GET", "http://localhost:8080/status", nil) - trace, err = httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) - assert.NoError(t, err) - assert.Equal(t, 401, trace.Response.StatusCode) - - // status page with auth - req, _ = http.NewRequest("GET", "http://localhost:8080/status", nil) - req.SetBasicAuth("admin", "password123") - trace, err = httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) - assert.NoError(t, err) - assert.Contains(t, string(trace.ResponseBody), "courier") - - // hit an invalid path - req, _ = http.NewRequest("GET", "http://localhost:8080/notthere", nil) - trace, err = httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) - assert.NoError(t, err) - assert.Contains(t, string(trace.ResponseBody), "not found") - - // invalid method - req, _ = http.NewRequest("POST", "http://localhost:8080/", nil) - trace, err = httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) - assert.NoError(t, err) - assert.Contains(t, string(trace.ResponseBody), "method not allowed") + request := func(method, url, user, pass string) (int, string) { + req, _ := http.NewRequest(method, url, nil) + if user != "" { + req.SetBasicAuth(user, pass) + } + trace, err := httpx.DoTrace(http.DefaultClient, req, nil, nil, 0) + require.NoError(t, err) + return trace.Response.StatusCode, string(trace.ResponseBody) + } + + // route listing at the / root + statusCode, respBody := request("GET", "http://localhost:8080/", "", "") + assert.Equal(t, 200, statusCode) + assert.Contains(t, respBody, "/c/mck/{uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}/receive - Mock Handler receive") + + // can't access status page without auth + statusCode, respBody = request("GET", "http://localhost:8080/status", "", "") + assert.Equal(t, 401, statusCode) + assert.Contains(t, respBody, "Unauthorized") + + // can access status page without auth + statusCode, respBody = request("GET", "http://localhost:8080/status", "admin", "password123") + assert.Equal(t, 200, statusCode) + assert.Contains(t, respBody, "ALL GOOD") + + // can't access status page with wrong method + statusCode, respBody = request("POST", "http://localhost:8080/status", "admin", "password123") + assert.Equal(t, 405, statusCode) + assert.Contains(t, respBody, "Method Not Allowed") + + // can't access non-existent page + statusCode, respBody = request("POST", "http://localhost:8080/nothere", "admin", "password123") + assert.Equal(t, 404, statusCode) + assert.Contains(t, respBody, "not found") } diff --git a/test/backend.go b/test/backend.go index 99f147dbb..38571a025 100644 --- a/test/backend.go +++ b/test/backend.go @@ -345,7 +345,7 @@ func (mb *MockBackend) Health() string { // Status returns a string describing the status of the service, queue size etc.. func (mb *MockBackend) Status() string { - return "" + return "ALL GOOD" } // Heartbeat is a noop for our mock backend From f589f4948a0ccd716127170b682573dc3f05cd7c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 6 Oct 2022 09:32:03 -0500 Subject: [PATCH 224/294] Less passing around of unused contexts --- handlers/base.go | 8 ++++---- handlers/external/external.go | 4 ++-- handlers/facebook/facebook.go | 2 +- handlers/facebookapp/facebookapp.go | 4 ++-- handlers/infobip/infobip.go | 2 +- handlers/jiochat/jiochat.go | 2 +- handlers/junebug/junebug.go | 4 ++-- handlers/mtarget/mtarget.go | 2 +- handlers/novo/novo.go | 2 +- handlers/rocketchat/rocketchat.go | 2 +- handlers/telegram/telegram.go | 2 +- handlers/viber/viber.go | 6 +++--- handlers/wechat/wechat.go | 2 +- handlers/whatsapp/whatsapp.go | 4 ++-- responses.go | 30 ++++++++++++++--------------- responses_test.go | 16 +++++---------- server.go | 4 ++-- test/handler.go | 8 ++++---- 18 files changed, 49 insertions(+), 55 deletions(-) diff --git a/handlers/base.go b/handlers/base.go index b3c2e67b6..950ed158d 100644 --- a/handlers/base.go +++ b/handlers/base.go @@ -93,20 +93,20 @@ func (h *BaseHandler) GetChannel(ctx context.Context, r *http.Request) (courier. // WriteStatusSuccessResponse writes a success response for the statuses func (h *BaseHandler) WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, statuses []courier.MsgStatus) error { - return courier.WriteStatusSuccess(ctx, w, statuses) + return courier.WriteStatusSuccess(w, statuses) } // WriteMsgSuccessResponse writes a success response for the messages func (h *BaseHandler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { - return courier.WriteMsgSuccess(ctx, w, msgs) + return courier.WriteMsgSuccess(w, msgs) } // WriteRequestError writes the passed in error to our response writer func (h *BaseHandler) WriteRequestError(ctx context.Context, w http.ResponseWriter, err error) error { - return courier.WriteError(ctx, w, http.StatusBadRequest, err) + return courier.WriteError(w, http.StatusBadRequest, err) } // WriteRequestIgnored writes an ignored payload to our response writer func (h *BaseHandler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter, details string) error { - return courier.WriteIgnored(ctx, w, details) + return courier.WriteIgnored(w, details) } diff --git a/handlers/external/external.go b/handlers/external/external.go index 1cc2fe24c..fae13ca0d 100644 --- a/handlers/external/external.go +++ b/handlers/external/external.go @@ -116,7 +116,7 @@ func (h *handler) receiveStopContact(ctx context.Context, channel courier.Channe if err != nil { return nil, err } - return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(ctx, w, channelEvent) + return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(w, channelEvent) } // utility function to grab the form value for either the passed in name (if non-empty) or the first set @@ -223,7 +223,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { moResponse := msgs[0].Channel().StringConfigForKey(configMOResponse, "") if moResponse == "" { - return courier.WriteMsgSuccess(ctx, w, msgs) + return courier.WriteMsgSuccess(w, msgs) } moResponseContentType := msgs[0].Channel().StringConfigForKey(configMOResponseContentType, "") if moResponseContentType != "" { diff --git a/handlers/facebook/facebook.go b/handlers/facebook/facebook.go index 752436f49..124fd9ee3 100644 --- a/handlers/facebook/facebook.go +++ b/handlers/facebook/facebook.go @@ -434,7 +434,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } } - return events, courier.WriteDataResponse(ctx, w, http.StatusOK, "Events Handled", data) + return events, courier.WriteDataResponse(w, http.StatusOK, "Events Handled", data) } // { diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index f58ddf7f9..a37fe0c13 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -274,7 +274,7 @@ func (h *handler) RedactValues(ch courier.Channel) []string { // WriteRequestError writes the passed in error to our response writer func (h *handler) WriteRequestError(ctx context.Context, w http.ResponseWriter, err error) error { - return courier.WriteError(ctx, w, http.StatusOK, err) + return courier.WriteError(w, http.StatusOK, err) } // GetChannel returns the channel @@ -400,7 +400,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, err } - return events, courier.WriteDataResponse(ctx, w, http.StatusOK, "Events Handled", data) + return events, courier.WriteDataResponse(w, http.StatusOK, "Events Handled", data) } func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel courier.Channel, payload *moPayload, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, []interface{}, error) { diff --git a/handlers/infobip/infobip.go b/handlers/infobip/infobip.go index 2e53e10a8..e604ab39c 100644 --- a/handlers/infobip/infobip.go +++ b/handlers/infobip/infobip.go @@ -88,7 +88,7 @@ func (h *handler) statusMessage(ctx context.Context, channel courier.Channel, w statuses = append(statuses, status) } - return statuses, courier.WriteDataResponse(ctx, w, http.StatusOK, "statuses handled", data) + return statuses, courier.WriteDataResponse(w, http.StatusOK, "statuses handled", data) } // { diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index d664a8c00..3f0dcf571 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -136,7 +136,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return nil, err } - return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(ctx, w, channelEvent) + return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(w, channelEvent) } // unknown event type (we only deal with subscribe) diff --git a/handlers/junebug/junebug.go b/handlers/junebug/junebug.go index ccfd9e94c..b55d7ad14 100644 --- a/handlers/junebug/junebug.go +++ b/handlers/junebug/junebug.go @@ -68,7 +68,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. if secret != "" { authorization := r.Header.Get("Authorization") if authorization != fmt.Sprintf("Token %s", secret) { - return nil, courier.WriteAndLogUnauthorized(ctx, w, r, c, fmt.Errorf("invalid Authorization header")) + return nil, courier.WriteAndLogUnauthorized(w, r, c, fmt.Errorf("invalid Authorization header")) } } @@ -120,7 +120,7 @@ func (h *handler) receiveEvent(ctx context.Context, c courier.Channel, w http.Re if secret != "" { authorization := r.Header.Get("Authorization") if authorization != fmt.Sprintf("Token %s", secret) { - return nil, courier.WriteAndLogUnauthorized(ctx, w, r, c, fmt.Errorf("invalid Authorization header")) + return nil, courier.WriteAndLogUnauthorized(w, r, c, fmt.Errorf("invalid Authorization header")) } } diff --git a/handlers/mtarget/mtarget.go b/handlers/mtarget/mtarget.go index db74394ef..8fb19a05e 100644 --- a/handlers/mtarget/mtarget.go +++ b/handlers/mtarget/mtarget.go @@ -138,7 +138,7 @@ func (h *handler) receiveMsg(ctx context.Context, c courier.Channel, w http.Resp if err != nil { return nil, err } - return []courier.Event{stop}, courier.WriteChannelEventSuccess(ctx, w, stop) + return []courier.Event{stop}, courier.WriteChannelEventSuccess(w, stop) } // otherwise, create our incoming message and write that diff --git a/handlers/novo/novo.go b/handlers/novo/novo.go index 2234a3f04..e76f3a9da 100644 --- a/handlers/novo/novo.go +++ b/handlers/novo/novo.go @@ -51,7 +51,7 @@ func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http. if secret != "" { authorization := r.Header.Get("Authorization") if authorization != secret { - return nil, courier.WriteAndLogUnauthorized(ctx, w, r, c, fmt.Errorf("invalid Authorization header")) + return nil, courier.WriteAndLogUnauthorized(w, r, c, fmt.Errorf("invalid Authorization header")) } } diff --git a/handlers/rocketchat/rocketchat.go b/handlers/rocketchat/rocketchat.go index ee01a95f1..1317b5591 100644 --- a/handlers/rocketchat/rocketchat.go +++ b/handlers/rocketchat/rocketchat.go @@ -62,7 +62,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w // check authorization secret := channel.StringConfigForKey(configSecret, "") if fmt.Sprintf("Token %s", secret) != r.Header.Get("Authorization") { - return nil, courier.WriteAndLogUnauthorized(ctx, w, r, channel, fmt.Errorf("invalid Authorization header")) + return nil, courier.WriteAndLogUnauthorized(w, r, channel, fmt.Errorf("invalid Authorization header")) } payload := &moPayload{} diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index 63da3227a..ae79ae067 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -83,7 +83,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w if err != nil { return nil, err } - return []courier.Event{event}, courier.WriteChannelEventSuccess(ctx, w, event) + return []courier.Event{event}, courier.WriteChannelEventSuccess(w, event) } // normal message of some kind diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index 0eb5c09c8..515be0b8f 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -148,7 +148,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, err } - return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(ctx, w, channelEvent) + return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(w, channelEvent) case "unsubscribed": viberID := payload.UserID @@ -166,7 +166,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, err } - return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(ctx, w, channelEvent) + return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(w, channelEvent) case "failed": msgStatus := h.Backend().NewMsgStatusForExternalID(channel, fmt.Sprintf("%d", payload.MessageToken), courier.MsgFailed, clog) @@ -235,7 +235,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } - return nil, courier.WriteError(ctx, w, http.StatusBadRequest, fmt.Errorf("not handled, unknown event: %s", event)) + return nil, courier.WriteError(w, http.StatusBadRequest, fmt.Errorf("not handled, unknown event: %s", event)) } func writeWelcomeMessageResponse(w http.ResponseWriter, channel courier.Channel, event courier.Event) error { diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index 2b0adcbbc..ceff631ad 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -195,7 +195,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return nil, err } - return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(ctx, w, channelEvent) + return []courier.Event{channelEvent}, courier.WriteChannelEventSuccess(w, channelEvent) } // unknown event type (we only deal with subscribe) diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index 88c66835c..f755b7f14 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -295,7 +295,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h data = append(data, courier.NewStatusData(event)) } - return events, courier.WriteDataResponse(ctx, w, http.StatusOK, "Events Handled", data) + return events, courier.WriteDataResponse(w, http.StatusOK, "Events Handled", data) } func resolveMediaURL(channel courier.Channel, mediaID string) (string, error) { @@ -570,7 +570,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // WriteRequestError writes the passed in error to our response writer func (h *handler) WriteRequestError(ctx context.Context, w http.ResponseWriter, err error) error { - return courier.WriteError(ctx, w, http.StatusOK, err) + return courier.WriteError(w, http.StatusOK, err) } func buildPayloads(msg courier.Msg, h *handler, clog *courier.ChannelLog) ([]interface{}, error) { diff --git a/responses.go b/responses.go index 346b7f009..94b8d6900 100644 --- a/responses.go +++ b/responses.go @@ -19,7 +19,7 @@ func writeAndLogRequestError(ctx context.Context, h ChannelHandler, w http.Respo } // WriteError writes a JSON response for the passed in error -func WriteError(ctx context.Context, w http.ResponseWriter, statusCode int, err error) error { +func WriteError(w http.ResponseWriter, statusCode int, err error) error { errors := []interface{}{NewErrorData(err.Error())} vErrs, isValidation := err.(validator.ValidationErrors) @@ -28,48 +28,48 @@ func WriteError(ctx context.Context, w http.ResponseWriter, statusCode int, err errors = append(errors, NewErrorData(fmt.Sprintf("field '%s' %s", strings.ToLower(vErrs[i].Field()), vErrs[i].Tag()))) } } - return WriteDataResponse(ctx, w, statusCode, "Error", errors) + return WriteDataResponse(w, statusCode, "Error", errors) } // WriteIgnored writes a JSON response indicating that we ignored the request -func WriteIgnored(ctx context.Context, w http.ResponseWriter, details string) error { - return WriteDataResponse(ctx, w, http.StatusOK, "Ignored", []interface{}{NewInfoData(details)}) +func WriteIgnored(w http.ResponseWriter, details string) error { + return WriteDataResponse(w, http.StatusOK, "Ignored", []interface{}{NewInfoData(details)}) } // WriteAndLogUnauthorized writes a JSON response for the passed in message and logs an info message -func WriteAndLogUnauthorized(ctx context.Context, w http.ResponseWriter, r *http.Request, c Channel, err error) error { +func WriteAndLogUnauthorized(w http.ResponseWriter, r *http.Request, c Channel, err error) error { LogRequestError(r, c, err) - return WriteDataResponse(ctx, w, http.StatusUnauthorized, "Unauthorized", []interface{}{NewErrorData(err.Error())}) + return WriteDataResponse(w, http.StatusUnauthorized, "Unauthorized", []interface{}{NewErrorData(err.Error())}) } // WriteChannelEventSuccess writes a JSON response for the passed in event indicating we handled it -func WriteChannelEventSuccess(ctx context.Context, w http.ResponseWriter, event ChannelEvent) error { - return WriteDataResponse(ctx, w, http.StatusOK, "Event Accepted", []interface{}{NewEventReceiveData(event)}) +func WriteChannelEventSuccess(w http.ResponseWriter, event ChannelEvent) error { + return WriteDataResponse(w, http.StatusOK, "Event Accepted", []interface{}{NewEventReceiveData(event)}) } // WriteMsgSuccess writes a JSON response for the passed in msg indicating we handled it -func WriteMsgSuccess(ctx context.Context, w http.ResponseWriter, msgs []Msg) error { +func WriteMsgSuccess(w http.ResponseWriter, msgs []Msg) error { data := []interface{}{} for _, msg := range msgs { data = append(data, NewMsgReceiveData(msg)) } - return WriteDataResponse(ctx, w, http.StatusOK, "Message Accepted", data) + return WriteDataResponse(w, http.StatusOK, "Message Accepted", data) } // WriteStatusSuccess writes a JSON response for the passed in status update indicating we handled it -func WriteStatusSuccess(ctx context.Context, w http.ResponseWriter, statuses []MsgStatus) error { +func WriteStatusSuccess(w http.ResponseWriter, statuses []MsgStatus) error { data := []interface{}{} for _, status := range statuses { data = append(data, NewStatusData(status)) } - return WriteDataResponse(ctx, w, http.StatusOK, "Status Update Accepted", data) + return WriteDataResponse(w, http.StatusOK, "Status Update Accepted", data) } // WriteDataResponse writes a JSON formatted response with the passed in status code, message and data -func WriteDataResponse(ctx context.Context, w http.ResponseWriter, statusCode int, message string, data []interface{}) error { - return writeJSONResponse(ctx, w, statusCode, &dataResponse{message, data}) +func WriteDataResponse(w http.ResponseWriter, statusCode int, message string, data []interface{}) error { + return writeJSONResponse(w, statusCode, &dataResponse{message, data}) } // MsgReceiveData is our response payload for a received message @@ -167,7 +167,7 @@ type dataResponse struct { Data []interface{} `json:"data"` } -func writeJSONResponse(ctx context.Context, w http.ResponseWriter, statusCode int, response interface{}) error { +func writeJSONResponse(w http.ResponseWriter, statusCode int, response interface{}) error { w.Header().Set("Content-Type", "application/json") w.WriteHeader(statusCode) return json.NewEncoder(w).Encode(response) diff --git a/responses_test.go b/responses_test.go index 58a3a5d5e..666108be7 100644 --- a/responses_test.go +++ b/responses_test.go @@ -1,7 +1,6 @@ package courier_test import ( - "context" "errors" "net/http" "net/http/httptest" @@ -14,56 +13,51 @@ import ( ) func TestWriteError(t *testing.T) { - ctx := context.Background() w := httptest.NewRecorder() - err := courier.WriteError(ctx, w, 406, errors.New("boom")) + err := courier.WriteError(w, 406, errors.New("boom")) assert.NoError(t, err) assert.Equal(t, 406, w.Code) assert.Equal(t, "{\"message\":\"Error\",\"data\":[{\"type\":\"error\",\"error\":\"boom\"}]}\n", w.Body.String()) } func TestWriteIgnored(t *testing.T) { - ctx := context.Background() w := httptest.NewRecorder() - err := courier.WriteIgnored(ctx, w, "why you calling") + err := courier.WriteIgnored(w, "why you calling") assert.NoError(t, err) assert.Equal(t, 200, w.Code) assert.Equal(t, "{\"message\":\"Ignored\",\"data\":[{\"type\":\"info\",\"info\":\"why you calling\"}]}\n", w.Body.String()) } func TestWriteAndLogUnauthorized(t *testing.T) { - ctx := context.Background() ch := test.NewMockChannel("5fccf4b6-48d7-4f5a-bce8-b0d1fd5342ec", "NX", "+1234567890", "US", nil) r, _ := http.NewRequest("GET", "http://example.com", nil) w := httptest.NewRecorder() - err := courier.WriteAndLogUnauthorized(ctx, w, r, ch, errors.New("wrong password")) + err := courier.WriteAndLogUnauthorized(w, r, ch, errors.New("wrong password")) assert.NoError(t, err) assert.Equal(t, 401, w.Code) assert.Equal(t, "{\"message\":\"Unauthorized\",\"data\":[{\"type\":\"error\",\"error\":\"wrong password\"}]}\n", w.Body.String()) } func TestWriteMsgSuccess(t *testing.T) { - ctx := context.Background() ch := test.NewMockChannel("5fccf4b6-48d7-4f5a-bce8-b0d1fd5342ec", "NX", "+1234567890", "US", nil) msg := test.NewMockBackend().NewIncomingMsg(ch, "tel:+0987654321", "hi there", nil).WithUUID(courier.NewMsgUUIDFromString("588aafc4-ab5c-48ce-89e8-05c9fdeeafb7")) w := httptest.NewRecorder() - err := courier.WriteMsgSuccess(ctx, w, []courier.Msg{msg}) + err := courier.WriteMsgSuccess(w, []courier.Msg{msg}) assert.NoError(t, err) assert.Equal(t, 200, w.Code) assert.Equal(t, "{\"message\":\"Message Accepted\",\"data\":[{\"type\":\"msg\",\"channel_uuid\":\"5fccf4b6-48d7-4f5a-bce8-b0d1fd5342ec\",\"msg_uuid\":\"588aafc4-ab5c-48ce-89e8-05c9fdeeafb7\",\"text\":\"hi there\",\"urn\":\"tel:+0987654321\"}]}\n", w.Body.String()) } func TestWriteChannelEventSuccess(t *testing.T) { - ctx := context.Background() ch := test.NewMockChannel("5fccf4b6-48d7-4f5a-bce8-b0d1fd5342ec", "NX", "+1234567890", "US", nil) evt := test.NewMockBackend().NewChannelEvent(ch, courier.StopContact, "tel:+0987654321", nil).WithOccurredOn(time.Date(2022, 9, 15, 12, 7, 30, 0, time.UTC)) w := httptest.NewRecorder() - err := courier.WriteChannelEventSuccess(ctx, w, evt) + err := courier.WriteChannelEventSuccess(w, evt) assert.NoError(t, err) assert.Equal(t, 200, w.Code) assert.Equal(t, "{\"message\":\"Event Accepted\",\"data\":[{\"type\":\"event\",\"channel_uuid\":\"5fccf4b6-48d7-4f5a-bce8-b0d1fd5342ec\",\"event_type\":\"stop_contact\",\"urn\":\"tel:+0987654321\",\"received_on\":\"2022-09-15T12:07:30Z\"}]}\n", w.Body.String()) diff --git a/server.go b/server.go index d28cade41..fbf2c57b4 100644 --- a/server.go +++ b/server.go @@ -383,7 +383,7 @@ func (s *server) handleIndex(w http.ResponseWriter, r *http.Request) { func (s *server) handle404(w http.ResponseWriter, r *http.Request) { logrus.WithField("url", r.URL.String()).WithField("method", r.Method).WithField("resp_status", "404").Info("not found") errors := []interface{}{NewErrorData(fmt.Sprintf("not found: %s", r.URL.String()))} - err := WriteDataResponse(context.Background(), w, http.StatusNotFound, "Not Found", errors) + err := WriteDataResponse(w, http.StatusNotFound, "Not Found", errors) if err != nil { logrus.WithError(err).Error() } @@ -392,7 +392,7 @@ func (s *server) handle404(w http.ResponseWriter, r *http.Request) { func (s *server) handle405(w http.ResponseWriter, r *http.Request) { logrus.WithField("url", r.URL.String()).WithField("method", r.Method).WithField("resp_status", "405").Info("invalid method") errors := []interface{}{NewErrorData(fmt.Sprintf("method not allowed: %s", r.Method))} - err := WriteDataResponse(context.Background(), w, http.StatusMethodNotAllowed, "Method Not Allowed", errors) + err := WriteDataResponse(w, http.StatusMethodNotAllowed, "Method Not Allowed", errors) if err != nil { logrus.WithError(err).Error() } diff --git a/test/handler.go b/test/handler.go index e98c7891e..dc9d8ed5d 100644 --- a/test/handler.go +++ b/test/handler.go @@ -53,19 +53,19 @@ func (h *mockHandler) Send(ctx context.Context, msg courier.Msg, clog *courier.C } func (h *mockHandler) WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, statuses []courier.MsgStatus) error { - return courier.WriteStatusSuccess(ctx, w, statuses) + return courier.WriteStatusSuccess(w, statuses) } func (h *mockHandler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.Msg) error { - return courier.WriteMsgSuccess(ctx, w, msgs) + return courier.WriteMsgSuccess(w, msgs) } func (h *mockHandler) WriteRequestError(ctx context.Context, w http.ResponseWriter, err error) error { - return courier.WriteError(ctx, w, http.StatusBadRequest, err) + return courier.WriteError(w, http.StatusBadRequest, err) } func (h *mockHandler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter, details string) error { - return courier.WriteIgnored(ctx, w, details) + return courier.WriteIgnored(w, details) } // ReceiveMsg sends the passed in message, returning any error From 960877109e21b09250c2fe3a66a1c49832a1b8b5 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 6 Oct 2022 09:57:05 -0500 Subject: [PATCH 225/294] Reorg some stuff in server.go --- server.go | 62 ++++++++++++++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/server.go b/server.go index fbf2c57b4..72b897b6c 100644 --- a/server.go +++ b/server.go @@ -23,6 +23,14 @@ import ( "github.com/sirupsen/logrus" ) +// for use in request.Context +type contextKey int + +const ( + contextRequestURL contextKey = iota + contextRequestStart +) + // Server is the main interface ChannelHandlers use to interact with backends. It provides an // abstraction that makes mocking easier for isolated unit tests type Server interface { @@ -106,7 +114,7 @@ func (s *server) Start() error { s.router.NotFound(s.handle404) s.router.MethodNotAllowed(s.handle405) s.router.Get("/", s.handleIndex) - s.router.Get("/status", s.handleStatus) + s.router.Get("/status", s.authRequiredHandler(s.handleStatus)) // initialize our handlers s.initializeChannelHandlers() @@ -126,11 +134,7 @@ func (s *server) Start() error { defer s.waitGroup.Done() err := s.httpServer.ListenAndServe() if err != nil && err != http.ErrServerClosed { - logrus.WithFields(logrus.Fields{ - "comp": "server", - "state": "stopping", - "err": err, - }).Error() + logrus.WithFields(logrus.Fields{"comp": "server", "state": "stopping"}).Error(err) } }() @@ -366,17 +370,26 @@ func (s *server) AddHandlerRoute(handler ChannelHandler, method string, action s } func (s *server) handleIndex(w http.ResponseWriter, r *http.Request) { - var buf bytes.Buffer - buf.WriteString("courier

\n")
+	buf.WriteString("courier
\n")
 	buf.WriteString(splash)
 	buf.WriteString(s.config.Version)
-
 	buf.WriteString(s.backend.Health())
-
 	buf.WriteString("\n\n")
 	buf.WriteString(strings.Join(s.chanRoutes, "\n"))
-	buf.WriteString("
") + buf.WriteString("
") + w.Write(buf.Bytes()) +} + +func (s *server) handleStatus(w http.ResponseWriter, r *http.Request) { + var buf bytes.Buffer + buf.WriteString("courier
\n")
+	buf.WriteString(splash)
+	buf.WriteString(s.config.Version)
+	buf.WriteString("\n\n")
+	buf.WriteString(s.backend.Status())
+	buf.WriteString("\n\n")
+	buf.WriteString("
") w.Write(buf.Bytes()) } @@ -398,37 +411,20 @@ func (s *server) handle405(w http.ResponseWriter, r *http.Request) { } } -func (s *server) handleStatus(w http.ResponseWriter, r *http.Request) { - if s.config.StatusUsername != "" { +// wraps a handler to make it use basic auth +func (s *server) authRequiredHandler(h func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { user, pass, ok := r.BasicAuth() if !ok || user != s.config.StatusUsername || pass != s.config.StatusPassword { w.Header().Set("WWW-Authenticate", `Basic realm="Authenticate"`) - w.WriteHeader(401) + w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Unauthorized.\n")) return } + h(w, r) } - - var buf bytes.Buffer - buf.WriteString("courier
\n")
-	buf.WriteString(splash)
-	buf.WriteString(s.config.Version)
-
-	buf.WriteString("\n\n")
-	buf.WriteString(s.backend.Status())
-	buf.WriteString("\n\n")
-	buf.WriteString("
") - w.Write(buf.Bytes()) } -// for use in request.Context -type contextKey int - -const ( - contextRequestURL contextKey = iota - contextRequestStart -) - var splash = ` ____________ _____ ___ ____/_________ ___________(_)____________ From b7528c21779658cc42e9af732eb7ffa81971b3c4 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 6 Oct 2022 11:38:11 -0500 Subject: [PATCH 226/294] Update CHANGELOG.md for v7.5.44 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18fc91b89..c5ad9f79d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.44 +---------- + * Add endpoint to download and store attachments by their URL + v7.5.43 ---------- * Update dependencies From fbf458997f65230d8014958abfbfbbb80773aae5 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 6 Oct 2022 12:05:51 -0500 Subject: [PATCH 227/294] Basic auth on status endpoint should be optional --- server.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/server.go b/server.go index a36c3aed8..98cddc7bb 100644 --- a/server.go +++ b/server.go @@ -432,12 +432,14 @@ func (s *server) handle405(w http.ResponseWriter, r *http.Request) { // wraps a handler to make it use basic auth func (s *server) basicAuthRequired(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - user, pass, ok := r.BasicAuth() - if !ok || user != s.config.StatusUsername || pass != s.config.StatusPassword { - w.Header().Set("WWW-Authenticate", `Basic realm="Authenticate"`) - w.WriteHeader(http.StatusUnauthorized) - w.Write([]byte("Unauthorized")) - return + if s.config.StatusUsername != "" { + user, pass, ok := r.BasicAuth() + if !ok || user != s.config.StatusUsername || pass != s.config.StatusPassword { + w.Header().Set("WWW-Authenticate", `Basic realm="Authenticate"`) + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte("Unauthorized")) + return + } } h(w, r) } From a84dffa8da87285101a63c7e937e6fd9ceb2bbd1 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 6 Oct 2022 12:12:39 -0500 Subject: [PATCH 228/294] Update CHANGELOG.md for v7.5.45 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5ad9f79d..27894e6af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.45 +---------- + * Basic auth on status endpoint should be optional + v7.5.44 ---------- * Add endpoint to download and store attachments by their URL From 9be28f1d1285b2077a8827d4e93fc4f1e1ae4426 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 7 Oct 2022 12:13:24 -0500 Subject: [PATCH 229/294] Rework attachment fetching to keep URL and content type separate --- attachments.go | 36 ++++++++++++++++++++----------- attachments_test.go | 7 +++--- backends/rapidpro/backend.go | 5 ++--- backends/rapidpro/backend_test.go | 2 +- backends/rapidpro/msg.go | 11 ++++++---- backends/rapidpro/task.go | 6 +++--- server.go | 4 ++-- server_test.go | 2 +- 8 files changed, 43 insertions(+), 30 deletions(-) diff --git a/attachments.go b/attachments.go index a1e2f04af..1d35d4d20 100644 --- a/attachments.go +++ b/attachments.go @@ -20,46 +20,52 @@ const ( maxAttBodyReadBytes = 100 * 1024 * 1024 ) +type Attachment struct { + ContentType string `json:"content_type"` + URL string `json:"url"` + Size int `json:"size"` +} + type fetchAttachmentRequest struct { ChannelType ChannelType `json:"channel_type" validate:"required"` ChannelUUID ChannelUUID `json:"channel_uuid" validate:"required,uuid"` URL string `json:"url" validate:"required"` } -func fetchAttachment(ctx context.Context, b Backend, r *http.Request) (string, int, *ChannelLog, error) { +func fetchAttachment(ctx context.Context, b Backend, r *http.Request) (*Attachment, *ChannelLog, error) { body, err := io.ReadAll(r.Body) if err != nil { - return "", 0, nil, errors.Wrap(err, "error reading request body") + return nil, nil, errors.Wrap(err, "error reading request body") } fa := &fetchAttachmentRequest{} if err := json.Unmarshal(body, fa); err != nil { - return "", 0, nil, errors.Wrap(err, "error unmarshalling request") + return nil, nil, errors.Wrap(err, "error unmarshalling request") } if err := utils.Validate(fa); err != nil { - return "", 0, nil, err + return nil, nil, err } ch, err := b.GetChannel(ctx, fa.ChannelType, fa.ChannelUUID) if err != nil { - return "", 0, nil, errors.Wrap(err, "error getting channel") + return nil, nil, errors.Wrap(err, "error getting channel") } clog := NewChannelLogForAttachmentFetch(ch, GetHandler(ch.ChannelType()).RedactValues(ch)) - newURL, size, err := FetchAndStoreAttachment(ctx, b, ch, fa.URL, clog) + attachment, err := FetchAndStoreAttachment(ctx, b, ch, fa.URL, clog) if err := b.WriteChannelLog(ctx, clog); err != nil { logrus.WithError(err).Error() } - return newURL, size, clog, err + return attachment, clog, err } -func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, attURL string, clog *ChannelLog) (string, int, error) { +func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, attURL string, clog *ChannelLog) (*Attachment, error) { parsedURL, err := url.Parse(attURL) if err != nil { - return "", 0, err + return nil, err } var httpClient *http.Client @@ -76,7 +82,7 @@ func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, at } if err != nil { - return "", 0, errors.Wrap(err, "unable to create attachment request") + return nil, errors.Wrap(err, "unable to create attachment request") } trace, err := httpx.DoTrace(httpClient, attRequest, nil, nil, maxAttBodyReadBytes) @@ -84,7 +90,7 @@ func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, at clog.HTTP(trace) } if err != nil { - return "", 0, err + return nil, err } mimeType := "" @@ -120,6 +126,10 @@ func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, at } } - newURL, err := b.SaveAttachment(ctx, channel, mimeType, trace.ResponseBody, extension) - return newURL, len(trace.ResponseBody), err + storageURL, err := b.SaveAttachment(ctx, channel, mimeType, trace.ResponseBody, extension) + if err != nil { + return nil, err + } + + return &Attachment{ContentType: mimeType, URL: storageURL, Size: len(trace.ResponseBody)}, nil } diff --git a/attachments_test.go b/attachments_test.go index 2d2c61132..b7f445e74 100644 --- a/attachments_test.go +++ b/attachments_test.go @@ -32,10 +32,11 @@ func TestFetchAndStoreAttachment(t *testing.T) { clog := courier.NewChannelLogForAttachmentFetch(mockChannel, []string{"sesame"}) - newURL, size, err := courier.FetchAndStoreAttachment(ctx, mb, mockChannel, "http://mock.com/media/hello.jpg", clog) + att, err := courier.FetchAndStoreAttachment(ctx, mb, mockChannel, "http://mock.com/media/hello.jpg", clog) assert.NoError(t, err) - assert.Equal(t, "https://backend.com/attachments/cdf7ed27-5ad5-4028-b664-880fc7581c77.jpg", newURL) - assert.Equal(t, 17301, size) + assert.Equal(t, "image/jpeg", att.ContentType) + assert.Equal(t, "https://backend.com/attachments/cdf7ed27-5ad5-4028-b664-880fc7581c77.jpg", att.URL) + assert.Equal(t, 17301, att.Size) assert.Len(t, mb.SavedAttachments(), 1) assert.Equal(t, &test.SavedAttachment{Channel: mockChannel, ContentType: "image/jpeg", Data: testJPG, Extension: "jpg"}, mb.SavedAttachments()[0]) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 91a657e81..550f38351 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -421,13 +421,12 @@ func (b *backend) SaveAttachment(ctx context.Context, ch courier.Channel, conten path = fmt.Sprintf("/%s", path) } - s3URL, err := b.storage.Put(ctx, path, contentType, data) + storageURL, err := b.storage.Put(ctx, path, contentType, data) if err != nil { return "", errors.Wrapf(err, "error saving attachment to storage (bytes=%d)", len(data)) } - // return our new media URL, which is prefixed by our content type - return fmt.Sprintf("%s:%s", contentType, s3URL), nil + return storageURL, nil } // ResolveMedia resolves the passed in attachment URL to a media object diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index b13fa455f..f6957bb51 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -1114,7 +1114,7 @@ func (ts *BackendTestSuite) TestSaveAttachment() { newURL, err := ts.b.SaveAttachment(ctx, knChannel, "image/jpeg", testJPG, "jpg") ts.NoError(err) - ts.Equal("image/jpeg:_test_storage/media/1/c00e/5d67/c00e5d67-c275-4389-aded-7d8b151cbd5b.jpg", newURL) + ts.Equal("_test_storage/media/1/c00e/5d67/c00e5d67-c275-4389-aded-7d8b151cbd5b.jpg", newURL) } func (ts *BackendTestSuite) TestWriteMsg() { diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index 41f8f5513..3b8fa0fce 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -55,14 +55,17 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch // if we have attachment URLs, download them to our own storage for i, attURL := range m.Attachments_ { + contentType := "unknown" newURL := attURL - var err error if strings.HasPrefix(attURL, "http://") || strings.HasPrefix(attURL, "https://") { - newURL, _, err = courier.FetchAndStoreAttachment(ctx, b, channel, attURL, clog) + att, err := courier.FetchAndStoreAttachment(ctx, b, channel, attURL, clog) if err != nil { return err } + contentType = att.ContentType + newURL = att.URL + } else if strings.HasPrefix(attURL, "data:") { attData, err := base64.StdEncoding.DecodeString(attURL[5:]) if err != nil { @@ -70,7 +73,7 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch return errors.Wrap(err, "unable to decode attachment data") } - var contentType, extension string + var extension string fileType, _ := filetype.Match(attData[:300]) if fileType != filetype.Unknown { contentType = fileType.MIME.Value @@ -86,7 +89,7 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch } } - m.Attachments_[i] = newURL + m.Attachments_[i] = fmt.Sprintf("%s:%s", contentType, newURL) } // try to write it our db diff --git a/backends/rapidpro/task.go b/backends/rapidpro/task.go index 02f1aee48..9ba96f869 100644 --- a/backends/rapidpro/task.go +++ b/backends/rapidpro/task.go @@ -16,9 +16,9 @@ func queueMsgHandling(rc redis.Conn, c *DBContact, m *DBMsg) error { body := map[string]any{ "contact_id": c.ID_, "org_id": channel.OrgID_, - "channel_id": channel.ID_, // deprecated - "channel_uuid": channel.UUID_, - "channel_type": channel.ChannelType_, + "channel_id": channel.ID_, + "channel_uuid": channel.UUID_, // deprecated + "channel_type": channel.ChannelType_, // deprecated "msg_id": m.ID_, "msg_uuid": m.UUID_.String(), "msg_external_id": m.ExternalID(), diff --git a/server.go b/server.go index 98cddc7bb..aa3d3aed4 100644 --- a/server.go +++ b/server.go @@ -399,7 +399,7 @@ func (s *server) handleFetchAttachment(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(context.Background(), time.Minute*1) defer cancel() - newURL, size, clog, err := fetchAttachment(ctx, s.backend, r) + attachment, clog, err := fetchAttachment(ctx, s.backend, r) if err != nil { logrus.WithError(err).Error() WriteError(w, http.StatusBadRequest, err) @@ -408,7 +408,7 @@ func (s *server) handleFetchAttachment(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - w.Write(jsonx.MustMarshal(map[string]any{"url": newURL, "size": size, "log_uuid": clog.UUID()})) + w.Write(jsonx.MustMarshal(map[string]any{"attachment": attachment, "log_uuid": clog.UUID()})) } func (s *server) handle404(w http.ResponseWriter, r *http.Request) { diff --git a/server_test.go b/server_test.go index 8de18eb7e..408fc33bf 100644 --- a/server_test.go +++ b/server_test.go @@ -130,5 +130,5 @@ func TestFetchAttachment(t *testing.T) { statusCode, respBody = submit(`{"channel_uuid": "e4bb1578-29da-4fa5-a214-9da19dd24230", "channel_type": "MCK", "url": "http://mock.com/media/test.jpg"}`, "sesame") assert.Equal(t, 200, statusCode) - assert.JSONEq(t, `{"log_uuid":"c00e5d67-c275-4389-aded-7d8b151cbd5b", "size": 17301, "url": "https://backend.com/attachments/cdf7ed27-5ad5-4028-b664-880fc7581c77.jpg"}`, string(respBody)) + assert.JSONEq(t, `{"attachment": {"content_type": "image/jpeg", "url": "https://backend.com/attachments/cdf7ed27-5ad5-4028-b664-880fc7581c77.jpg", "size": 17301}, "log_uuid": "c00e5d67-c275-4389-aded-7d8b151cbd5b"}`, string(respBody)) } From 6528294755008f7356f5c66eced4ed02ff1b6099 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 10 Oct 2022 11:45:27 -0500 Subject: [PATCH 230/294] Update CHANGELOG.md for v7.5.46 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27894e6af..ac3edf794 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.46 +---------- + * Rework attachment fetching to keep URL and content type separate + v7.5.45 ---------- * Basic auth on status endpoint should be optional From 4cdb474569bfe52f80b18f91de09e63b4582c4ea Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 10 Oct 2022 16:34:04 -0500 Subject: [PATCH 231/294] Fix handling of geo attachments --- backends/rapidpro/backend_test.go | 10 ++++++++++ backends/rapidpro/msg.go | 13 ++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index f6957bb51..d0dfe0d69 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -1101,6 +1101,16 @@ func (ts *BackendTestSuite) TestWriteAttachment() { ts.Equal(1, len(msg.Attachments())) ts.True(strings.HasPrefix(msg.Attachments()[0], "image/jpeg:")) ts.True(strings.HasSuffix(msg.Attachments()[0], ".jpg")) + + // try a geo attachment + msg = ts.b.NewIncomingMsg(knChannel, urn, "geo attachment", clog).(*DBMsg) + msg.WithAttachment("geo:123.234,-45.676") + + err = ts.b.WriteMsg(ctx, msg, clog) + ts.NoError(err) + + ts.Equal(1, len(msg.Attachments())) + ts.Equal("geo:123.234,-45.676", msg.Attachments()[0]) } func (ts *BackendTestSuite) TestSaveAttachment() { diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index 3b8fa0fce..fe67b4dc6 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -55,16 +55,14 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch // if we have attachment URLs, download them to our own storage for i, attURL := range m.Attachments_ { - contentType := "unknown" - newURL := attURL + resolved := attURL // geo links passed as is if strings.HasPrefix(attURL, "http://") || strings.HasPrefix(attURL, "https://") { att, err := courier.FetchAndStoreAttachment(ctx, b, channel, attURL, clog) if err != nil { return err } - contentType = att.ContentType - newURL = att.URL + resolved = fmt.Sprintf("%s:%s", att.ContentType, att.URL) } else if strings.HasPrefix(attURL, "data:") { attData, err := base64.StdEncoding.DecodeString(attURL[5:]) @@ -73,7 +71,7 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch return errors.Wrap(err, "unable to decode attachment data") } - var extension string + var contentType, extension string fileType, _ := filetype.Match(attData[:300]) if fileType != filetype.Unknown { contentType = fileType.MIME.Value @@ -83,13 +81,14 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch extension = "bin" } - newURL, err = b.SaveAttachment(ctx, channel, contentType, attData, extension) + newURL, err := b.SaveAttachment(ctx, channel, contentType, attData, extension) if err != nil { return err } + resolved = fmt.Sprintf("%s:%s", contentType, newURL) } - m.Attachments_[i] = fmt.Sprintf("%s:%s", contentType, newURL) + m.Attachments_[i] = resolved } // try to write it our db From 888acca5baf95ae7993521d6ef1e8baf41c5c0f9 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 10 Oct 2022 16:48:20 -0500 Subject: [PATCH 232/294] Update CHANGELOG.md for v7.5.47 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac3edf794..dbb08fc54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.47 +---------- + * Fix handling of geo attachments + v7.5.46 ---------- * Rework attachment fetching to keep URL and content type separate From 81da6980d157afb55bdfa12fe422202db665bc1b Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 12 Oct 2022 10:11:34 -0500 Subject: [PATCH 233/294] Stop fetching attachments and let message handling service do that via endpoint --- backends/rapidpro/backend_test.go | 143 ++++++++++-------------------- backends/rapidpro/msg.go | 18 +--- 2 files changed, 49 insertions(+), 112 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index d0dfe0d69..ede99f3c6 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -9,7 +9,6 @@ import ( "io" "log" "net/http" - "net/http/httptest" "net/url" "os" "strings" @@ -1016,103 +1015,6 @@ func (ts *BackendTestSuite) TestWriteChanneLog() { Columns(map[string]interface{}{"channel_id": int64(channel.ID()), "url": "https://api.messages.com/send.json", "err": "this is an error"}) } -func (ts *BackendTestSuite) TestWriteAttachment() { - ctx := context.Background() - - testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - defer r.Body.Close() - - content := "" - switch r.URL.Path { - case "/test.jpg": - content = "malformedjpegbody" - - case "/giffy": - content = "GIF87aandstuff" - - case "/header": - w.Header().Add("Content-Type", "image/png") - content = "nothingbody" - - default: - content = "unknown" - } - - w.Write([]byte(content)) - })) - - knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel, nil) - urn, _ := urns.NewTelURNForCountry("12065551215", knChannel.Country()) - msg := ts.b.NewIncomingMsg(knChannel, urn, "invalid attachment", clog).(*DBMsg) - msg.WithAttachment(testServer.URL) - - // should just end up being text/plain - err := ts.b.WriteMsg(ctx, msg, clog) - ts.NoError(err) - ts.True(strings.HasPrefix(msg.Attachments()[0], "text/plain")) - - // use an extension for our attachment instead - msg = ts.b.NewIncomingMsg(knChannel, urn, "jpg attachment", clog).(*DBMsg) - msg.WithAttachment(testServer.URL + "/test.jpg") - - err = ts.b.WriteMsg(ctx, msg, clog) - ts.NoError(err) - ts.True(strings.HasPrefix(msg.Attachments()[0], "image/jpeg:")) - ts.True(strings.HasSuffix(msg.Attachments()[0], ".jpg")) - - // ok, now derive it from magic bytes - msg = ts.b.NewIncomingMsg(knChannel, urn, "gif attachment", clog).(*DBMsg) - msg.WithAttachment(testServer.URL + "/giffy") - - err = ts.b.WriteMsg(ctx, msg, clog) - ts.NoError(err) - if ts.Equal(1, len(msg.Attachments())) { - ts.True(strings.HasPrefix(msg.Attachments()[0], "image/gif:")) - ts.True(strings.HasSuffix(msg.Attachments()[0], ".gif")) - } - - // finally from our header - msg = ts.b.NewIncomingMsg(knChannel, urn, "png attachment", clog).(*DBMsg) - msg.WithAttachment(testServer.URL + "/header") - - err = ts.b.WriteMsg(ctx, msg, clog) - ts.NoError(err) - if ts.Equal(1, len(msg.Attachments())) { - ts.True(strings.HasPrefix(msg.Attachments()[0], "image/png:")) - ts.True(strings.HasSuffix(msg.Attachments()[0], ".png")) - } - - // load it back from the id - m := readMsgFromDB(ts.b, msg.ID()) - - if ts.Equal(1, len(m.Attachments())) { - ts.True(strings.HasPrefix(m.Attachments()[0], "image/png:")) - ts.True(strings.HasSuffix(m.Attachments()[0], ".png")) - } - - // try embedded attachment - msg = ts.b.NewIncomingMsg(knChannel, urn, "embedded attachment", clog).(*DBMsg) - msg.WithAttachment(fmt.Sprintf("data:%s", base64.StdEncoding.EncodeToString(test.ReadFile("../../test/testdata/test.jpg")))) - - err = ts.b.WriteMsg(ctx, msg, clog) - ts.NoError(err) - - ts.Equal(1, len(msg.Attachments())) - ts.True(strings.HasPrefix(msg.Attachments()[0], "image/jpeg:")) - ts.True(strings.HasSuffix(msg.Attachments()[0], ".jpg")) - - // try a geo attachment - msg = ts.b.NewIncomingMsg(knChannel, urn, "geo attachment", clog).(*DBMsg) - msg.WithAttachment("geo:123.234,-45.676") - - err = ts.b.WriteMsg(ctx, msg, clog) - ts.NoError(err) - - ts.Equal(1, len(msg.Attachments())) - ts.Equal("geo:123.234,-45.676", msg.Attachments()[0]) -} - func (ts *BackendTestSuite) TestSaveAttachment() { testJPG := test.ReadFile("../../test/testdata/test.jpg") ctx := context.Background() @@ -1254,6 +1156,51 @@ func (ts *BackendTestSuite) TestWriteMsg() { }, body["task"]) } +func (ts *BackendTestSuite) TestWriteMsgWithAttachments() { + ctx := context.Background() + + defer uuids.SetGenerator(uuids.DefaultGenerator) + uuids.SetGenerator(uuids.NewSeededGenerator(1234)) + + knChannel := ts.getChannel("KN", "dbc126ed-66bc-4e28-b67b-81dc3327c95d") + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, knChannel, nil) + urn, _ := urns.NewTelURNForCountry("12065551218", knChannel.Country()) + + msg := ts.b.NewIncomingMsg(knChannel, urn, "two regular attachments", clog).(*DBMsg) + msg.WithAttachment("http://example.com/test.jpg") + msg.WithAttachment("http://example.com/test.m4a") + + // should just write attachments as they are + err := ts.b.WriteMsg(ctx, msg, clog) + ts.NoError(err) + ts.Equal([]string{"http://example.com/test.jpg", "http://example.com/test.m4a"}, msg.Attachments()) + + // try an embedded attachment + msg = ts.b.NewIncomingMsg(knChannel, urn, "embedded attachment data", clog).(*DBMsg) + msg.WithAttachment(fmt.Sprintf("data:%s", base64.StdEncoding.EncodeToString(test.ReadFile("../../test/testdata/test.jpg")))) + + // should have actually fetched and saved it to storage, with the correct content type + err = ts.b.WriteMsg(ctx, msg, clog) + ts.NoError(err) + ts.Equal([]string{"image/jpeg:_test_storage/media/1/547d/eaf7/547deaf7-7620-4434-95b3-58675999c4b7.jpg"}, msg.Attachments()) + + // try an invalid embedded attachment + msg = ts.b.NewIncomingMsg(knChannel, urn, "invalid embedded attachment data", clog).(*DBMsg) + msg.WithAttachment("data:34564363576573573") + + err = ts.b.WriteMsg(ctx, msg, clog) + ts.EqualError(err, "unable to decode attachment data: illegal base64 data at input byte 16") + + // try a geo attachment + msg = ts.b.NewIncomingMsg(knChannel, urn, "geo attachment", clog).(*DBMsg) + msg.WithAttachment("geo:123.234,-45.676") + + // should be saved as is + err = ts.b.WriteMsg(ctx, msg, clog) + ts.NoError(err) + ts.Equal([]string{"geo:123.234,-45.676"}, msg.Attachments()) +} + func (ts *BackendTestSuite) TestPreferredChannelCheckRole() { exChannel := ts.getChannel("EX", "dbc126ed-66bc-4e28-b67b-81dc3327100a") clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, exChannel, nil) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index fe67b4dc6..6814efa66 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -53,18 +53,10 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch channel := m.Channel() - // if we have attachment URLs, download them to our own storage + // check for data: attachment URLs which need to be fetched now - fetching of other URLs can be deferred until + // message handling and performed by calling the /c/_fetch-attachment endpoint for i, attURL := range m.Attachments_ { - resolved := attURL // geo links passed as is - - if strings.HasPrefix(attURL, "http://") || strings.HasPrefix(attURL, "https://") { - att, err := courier.FetchAndStoreAttachment(ctx, b, channel, attURL, clog) - if err != nil { - return err - } - resolved = fmt.Sprintf("%s:%s", att.ContentType, att.URL) - - } else if strings.HasPrefix(attURL, "data:") { + if strings.HasPrefix(attURL, "data:") { attData, err := base64.StdEncoding.DecodeString(attURL[5:]) if err != nil { clog.Error(courier.NewChannelError("Unable to decode attachment data.", "")) @@ -85,10 +77,8 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch if err != nil { return err } - resolved = fmt.Sprintf("%s:%s", contentType, newURL) + m.Attachments_[i] = fmt.Sprintf("%s:%s", contentType, newURL) } - - m.Attachments_[i] = resolved } // try to write it our db From 76b747c2f3a481cd3df57bbd49e50ff88012d1d3 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 13 Oct 2022 08:52:16 -0500 Subject: [PATCH 234/294] Fix handling non-200 responses from attachment fetches --- attachments.go | 5 +++++ attachments_test.go | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/attachments.go b/attachments.go index 1d35d4d20..59ea0353c 100644 --- a/attachments.go +++ b/attachments.go @@ -92,6 +92,11 @@ func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, at if err != nil { return nil, err } + if trace.Response.StatusCode/100 != 2 { + // TODO once we're confident this is working maybe we don't log errors like this since sometimes channels + // just have problems + return nil, errors.Errorf("non 2XX response code (%d) trying to fetch attachment", trace.Response.StatusCode) + } mimeType := "" extension := filepath.Ext(parsedURL.Path) diff --git a/attachments_test.go b/attachments_test.go index b7f445e74..4877c274a 100644 --- a/attachments_test.go +++ b/attachments_test.go @@ -19,6 +19,9 @@ func TestFetchAndStoreAttachment(t *testing.T) { "http://mock.com/media/hello.jpg": { httpx.NewMockResponse(200, nil, testJPG), }, + "http://mock.com/media/hello.mp3": { + httpx.NewMockResponse(502, nil, []byte(`Timeout`)), + }, })) defer uuids.SetGenerator(uuids.DefaultGenerator) @@ -42,4 +45,9 @@ func TestFetchAndStoreAttachment(t *testing.T) { assert.Equal(t, &test.SavedAttachment{Channel: mockChannel, ContentType: "image/jpeg", Data: testJPG, Extension: "jpg"}, mb.SavedAttachments()[0]) assert.Len(t, clog.HTTPLogs(), 1) assert.Equal(t, "http://mock.com/media/hello.jpg", clog.HTTPLogs()[0].URL) + + att, err = courier.FetchAndStoreAttachment(ctx, mb, mockChannel, "http://mock.com/media/hello.mp3", clog) + assert.EqualError(t, err, "non 2XX response code (502) trying to fetch attachment") + assert.Nil(t, att) + assert.Len(t, mb.SavedAttachments(), 1) } From 21ef0e96a720879b5a4d958b675059bef2db0b70 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 13 Oct 2022 09:15:00 -0500 Subject: [PATCH 235/294] Error if we try to fetch an attachment but get an empty response body --- attachments.go | 3 +++ attachments_test.go | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/attachments.go b/attachments.go index 59ea0353c..c7ea12a2c 100644 --- a/attachments.go +++ b/attachments.go @@ -97,6 +97,9 @@ func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, at // just have problems return nil, errors.Errorf("non 2XX response code (%d) trying to fetch attachment", trace.Response.StatusCode) } + if len(trace.ResponseBody) == 0 { + return nil, errors.New("received empty response trying to fetch attachment") + } mimeType := "" extension := filepath.Ext(parsedURL.Path) diff --git a/attachments_test.go b/attachments_test.go index 4877c274a..d89a25226 100644 --- a/attachments_test.go +++ b/attachments_test.go @@ -22,6 +22,9 @@ func TestFetchAndStoreAttachment(t *testing.T) { "http://mock.com/media/hello.mp3": { httpx.NewMockResponse(502, nil, []byte(`Timeout`)), }, + "http://mock.com/media/hello.avi": { + httpx.NewMockResponse(200, nil, nil), // 200 status code but empty response + }, })) defer uuids.SetGenerator(uuids.DefaultGenerator) @@ -50,4 +53,9 @@ func TestFetchAndStoreAttachment(t *testing.T) { assert.EqualError(t, err, "non 2XX response code (502) trying to fetch attachment") assert.Nil(t, att) assert.Len(t, mb.SavedAttachments(), 1) + + att, err = courier.FetchAndStoreAttachment(ctx, mb, mockChannel, "http://mock.com/media/hello.avi", clog) + assert.EqualError(t, err, "received empty response trying to fetch attachment") + assert.Nil(t, att) + assert.Len(t, mb.SavedAttachments(), 1) } From af00c6c0b2f72e0f7a03017851361521b5664911 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 13 Oct 2022 09:26:04 -0500 Subject: [PATCH 236/294] Update CHANGELOG.md for v7.5.48 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbb08fc54..c65c328cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.48 +---------- + * Fix handling empty and non-200 responses from attachment fetches + v7.5.47 ---------- * Fix handling of geo attachments From 8bbc1f435ca165571bc024642ad8c52c8af45ac8 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 13 Oct 2022 09:48:25 -0500 Subject: [PATCH 237/294] Update CHANGELOG.md for v7.5.49 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c65c328cf..e4adb994f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.49 +---------- + * Stop fetching attachments and let message handling service do that via endpoint + v7.5.48 ---------- * Fix handling empty and non-200 responses from attachment fetches From ecb65dd51995e00937220e8323b5dab7c2559efa Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 13 Oct 2022 15:05:43 -0500 Subject: [PATCH 238/294] Update to latest gocommon --- backends/rapidpro/backend.go | 5 +++-- backends/rapidpro/backend_test.go | 2 +- go.mod | 4 ++-- go.sum | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 550f38351..9a70fc35d 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -15,6 +15,7 @@ import ( "sync" "time" + "github.com/aws/aws-sdk-go/service/s3" "github.com/gomodule/redigo/redis" "github.com/jmoiron/sqlx" "github.com/nyaruka/courier" @@ -747,9 +748,9 @@ func (b *backend) Start() error { if err != nil { return err } - b.storage = storage.NewS3(s3Client, b.config.S3AttachmentsBucket, b.config.S3Region, 32) + b.storage = storage.NewS3(s3Client, b.config.S3AttachmentsBucket, b.config.S3Region, s3.BucketCannedACLPublicRead, 32) } else { - b.storage = storage.NewFS("_storage") + b.storage = storage.NewFS("_storage", 0766) } // test our storage diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index ede99f3c6..31994e8a7 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -82,7 +82,7 @@ func (ts *BackendTestSuite) SetupSuite() { r.Do("FLUSHDB") // use file storage instead of S3 - ts.b.storage = storage.NewFS(storageDir) + ts.b.storage = storage.NewFS(storageDir, 0766) } func (ts *BackendTestSuite) TearDownSuite() { diff --git a/go.mod b/go.mod index a2ced9847..726b785f9 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.19 require ( github.com/antchfx/xmlquery v1.3.12 + github.com/aws/aws-sdk-go v1.44.111 github.com/buger/jsonparser v1.1.1 github.com/dghubble/oauth1 v0.7.1 github.com/evalphobia/logrus_sentry v0.8.2 @@ -14,7 +15,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.6 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.31.0 + github.com/nyaruka/gocommon v1.32.0 github.com/nyaruka/null v1.2.0 github.com/nyaruka/redisx v0.2.2 github.com/patrickmn/go-cache v2.1.0+incompatible @@ -28,7 +29,6 @@ require ( require ( github.com/antchfx/xpath v1.2.1 // indirect - github.com/aws/aws-sdk-go v1.44.111 // indirect github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/structs v1.1.0 // indirect diff --git a/go.sum b/go.sum index aee51a2d4..bac74b328 100644 --- a/go.sum +++ b/go.sum @@ -77,8 +77,8 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.31.0 h1:eVRxmyTZxRQ4mBs3JoYaPe33LlNuQD63pxq2M+eHQA8= -github.com/nyaruka/gocommon v1.31.0/go.mod h1:PApT/06fP5Tzs4/kbkJ+rVoyOc9Lbqm1lR0ow8Vqzp0= +github.com/nyaruka/gocommon v1.32.0 h1:No9EGpym15WvWmbdNcKytvgQTpnEjTEyEf+doaaysSY= +github.com/nyaruka/gocommon v1.32.0/go.mod h1:PApT/06fP5Tzs4/kbkJ+rVoyOc9Lbqm1lR0ow8Vqzp0= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= From b628b8bdcf8aeb8453ab4aa800255497e53eb35c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 17 Oct 2022 09:38:02 -0500 Subject: [PATCH 239/294] Remove no longer used channel_uuid and channel_type fields from msg event payload queued to mailroom --- backends/rapidpro/backend_test.go | 2 -- backends/rapidpro/task.go | 2 -- 2 files changed, 4 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 31994e8a7..b196ad7ef 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -1142,8 +1142,6 @@ func (ts *BackendTestSuite) TestWriteMsg() { "contact_id": float64(contact.ID_), "org_id": float64(1), "channel_id": float64(10), - "channel_uuid": "dbc126ed-66bc-4e28-b67b-81dc3327c95d", - "channel_type": "KN", "msg_id": float64(msg.ID_), "msg_uuid": msg.UUID_.String(), "msg_external_id": msg.ExternalID(), diff --git a/backends/rapidpro/task.go b/backends/rapidpro/task.go index 9ba96f869..ac1a2f2a3 100644 --- a/backends/rapidpro/task.go +++ b/backends/rapidpro/task.go @@ -17,8 +17,6 @@ func queueMsgHandling(rc redis.Conn, c *DBContact, m *DBMsg) error { "contact_id": c.ID_, "org_id": channel.OrgID_, "channel_id": channel.ID_, - "channel_uuid": channel.UUID_, // deprecated - "channel_type": channel.ChannelType_, // deprecated "msg_id": m.ID_, "msg_uuid": m.UUID_.String(), "msg_external_id": m.ExternalID(), From e870be49fdfa1e72c4f794bf424a4508aa2101ba Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 17 Oct 2022 09:54:10 -0500 Subject: [PATCH 240/294] Remove created_on field which also isn't used --- backends/rapidpro/backend_test.go | 1 - backends/rapidpro/task.go | 1 - 2 files changed, 2 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index b196ad7ef..1aaef4e68 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -1150,7 +1150,6 @@ func (ts *BackendTestSuite) TestWriteMsg() { "text": msg.Text(), "attachments": nil, "new_contact": contact.IsNew_, - "created_on": msg.CreatedOn_.Format(time.RFC3339Nano), }, body["task"]) } diff --git a/backends/rapidpro/task.go b/backends/rapidpro/task.go index ac1a2f2a3..d8c73cf8a 100644 --- a/backends/rapidpro/task.go +++ b/backends/rapidpro/task.go @@ -25,7 +25,6 @@ func queueMsgHandling(rc redis.Conn, c *DBContact, m *DBMsg) error { "text": m.Text(), "attachments": m.Attachments(), "new_contact": c.IsNew_, - "created_on": m.CreatedOn_, } return queueMailroomTask(rc, "msg_event", m.OrgID_, m.ContactID_, body) From add7cd417731625cd52ea4b33bcf5f47e772c677 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 18 Oct 2022 10:07:45 -0500 Subject: [PATCH 241/294] Fix recording overall time of an attachment-fetch channel log --- attachments.go | 2 ++ server_test.go | 6 ++++++ test/backend.go | 2 ++ 3 files changed, 10 insertions(+) diff --git a/attachments.go b/attachments.go index c7ea12a2c..96b53d336 100644 --- a/attachments.go +++ b/attachments.go @@ -55,6 +55,8 @@ func fetchAttachment(ctx context.Context, b Backend, r *http.Request) (*Attachme attachment, err := FetchAndStoreAttachment(ctx, b, ch, fa.URL, clog) + clog.End() + if err := b.WriteChannelLog(ctx, clog); err != nil { logrus.WithError(err).Error() } diff --git a/server_test.go b/server_test.go index 408fc33bf..3c4220085 100644 --- a/server_test.go +++ b/server_test.go @@ -131,4 +131,10 @@ func TestFetchAttachment(t *testing.T) { statusCode, respBody = submit(`{"channel_uuid": "e4bb1578-29da-4fa5-a214-9da19dd24230", "channel_type": "MCK", "url": "http://mock.com/media/test.jpg"}`, "sesame") assert.Equal(t, 200, statusCode) assert.JSONEq(t, `{"attachment": {"content_type": "image/jpeg", "url": "https://backend.com/attachments/cdf7ed27-5ad5-4028-b664-880fc7581c77.jpg", "size": 17301}, "log_uuid": "c00e5d67-c275-4389-aded-7d8b151cbd5b"}`, string(respBody)) + + assert.Len(t, mb.WrittenChannelLogs(), 1) + clog := mb.WrittenChannelLogs()[0] + assert.Equal(t, courier.ChannelLogTypeAttachmentFetch, clog.Type()) + assert.Len(t, clog.HTTPLogs(), 1) + assert.Greater(t, clog.Elapsed(), time.Duration(0)) } diff --git a/test/backend.go b/test/backend.go index 0040c6317..f0154e036 100644 --- a/test/backend.go +++ b/test/backend.go @@ -309,6 +309,8 @@ func (mb *MockBackend) SaveAttachment(ctx context.Context, ch courier.Channel, c Channel: ch, ContentType: contentType, Data: data, Extension: extension, }) + time.Sleep(time.Millisecond * 2) + return fmt.Sprintf("https://backend.com/attachments/%s.%s", uuids.New(), extension), nil } From 906cb51a28c98046751d16abc168fc4e82f44c16 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 18 Oct 2022 11:03:19 -0500 Subject: [PATCH 242/294] Update CHANGELOG.md for v7.5.50 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4adb994f..fafa43dc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +v7.5.50 +---------- + * Fix recording overall time of an attachment-fetch channel log + * Remove no longer used channel_uuid and channel_type fields from msg event payload queued to mailroom + * Update to latest gocommon + v7.5.49 ---------- * Stop fetching attachments and let message handling service do that via endpoint From ce1e2b16f9d1f964b6b2075a53ed0011e3145981 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 19 Oct 2022 09:05:46 -0500 Subject: [PATCH 243/294] Tidy WA tests --- handlers/whatsapp/whatsapp_test.go | 212 ++++++++++++++++++++++++----- 1 file changed, 179 insertions(+), 33 deletions(-) diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index fbc50cf34..d51169e31 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -120,9 +120,7 @@ var documentMsg = `{ "timestamp": "1454119029", "type": "document", "document": { - "file": "/path/to/v1/media/41", "id": "41", - "link": "https://example.org/v1/media/41", "mime_type": "text/plain", "sha256": "the-sha-signature", "caption": "the caption", @@ -292,40 +290,188 @@ var ( ) var waTestCases = []ChannelHandleTestCase{ - {Label: "Receive Valid Message", URL: waReceiveURL, Data: helloMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, - ExpectedContactName: Sp("Jerry Cooney"), ExpectedMsgText: Sp("hello world"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + { + Label: "Receive Valid Message", + URL: waReceiveURL, + Data: helloMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"msg"`, + ExpectedContactName: Sp("Jerry Cooney"), + ExpectedMsgText: Sp("hello world"), + ExpectedURN: "whatsapp:250788123123", + ExpectedExternalID: "41", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), NoQueueErrorCheck: true, NoInvalidChannelCheck: true, }, - {Label: "Receive Duplicate Valid Message", URL: waReceiveURL, Data: duplicateMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, - ExpectedMsgText: Sp("hello world"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Audio Message", URL: waReceiveURL, Data: audioMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Button Message", URL: waReceiveURL, Data: buttonMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, - ExpectedMsgText: Sp("BUTTON1"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Document Message", URL: waReceiveURL, Data: documentMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, - ExpectedMsgText: Sp("the caption"), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Image Message", URL: waReceiveURL, Data: imageMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, - ExpectedMsgText: Sp("the caption"), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Interactive Button Message", URL: waReceiveURL, Data: interactiveButtonMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, - ExpectedMsgText: Sp("BUTTON1"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Interactive List Message", URL: waReceiveURL, Data: interactiveListMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, - ExpectedMsgText: Sp("ROW1"), ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Location Message", URL: waReceiveURL, Data: locationMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"geo:0.000000,1.000000"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Video Message", URL: waReceiveURL, Data: videoMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Valid Voice Message", URL: waReceiveURL, Data: voiceMsg, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"msg"`, - ExpectedMsgText: Sp(""), ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, ExpectedURN: "whatsapp:250788123123", ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC)}, - {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: invalidMsg, ExpectedRespStatus: 200, ExpectedBodyContains: "unable to parse"}, - {Label: "Receive Invalid From", URL: waReceiveURL, Data: invalidFrom, ExpectedRespStatus: 200, ExpectedBodyContains: "invalid whatsapp id"}, - {Label: "Receive Invalid Timestamp", URL: waReceiveURL, Data: invalidTimestamp, ExpectedRespStatus: 200, ExpectedBodyContains: "invalid timestamp"}, - - {Label: "Receive Valid Status", URL: waReceiveURL, Data: validStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `"type":"status"`, - ExpectedMsgStatus: "S", ExpectedExternalID: "9712A34B4A8B6AD50F"}, - {Label: "Receive Invalid JSON", URL: waReceiveURL, Data: "not json", ExpectedRespStatus: 200, ExpectedBodyContains: "unable to parse"}, - {Label: "Receive Invalid Status", URL: waReceiveURL, Data: invalidStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `"unknown status: in_orbit"`}, - {Label: "Receive Ignore Status", URL: waReceiveURL, Data: ignoreStatus, ExpectedRespStatus: 200, ExpectedBodyContains: `"ignoring status: deleted"`}, + { + Label: "Receive duplicate valid message", + URL: waReceiveURL, + Data: duplicateMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"msg"`, + ExpectedMsgText: Sp("hello world"), + ExpectedURN: "whatsapp:250788123123", + ExpectedExternalID: "41", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + }, + { + Label: "Receive valid audio message", + URL: waReceiveURL, + Data: audioMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"msg"`, + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, + ExpectedURN: "whatsapp:250788123123", + ExpectedExternalID: "41", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + }, + { + Label: "Receive valid button message", + URL: waReceiveURL, + Data: buttonMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"msg"`, + ExpectedMsgText: Sp("BUTTON1"), + ExpectedURN: "whatsapp:250788123123", + ExpectedExternalID: "41", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + }, + { + Label: "Receive valid document message", + URL: waReceiveURL, + Data: documentMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"msg"`, + ExpectedMsgText: Sp("the caption"), + ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, + ExpectedURN: "whatsapp:250788123123", + ExpectedExternalID: "41", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + }, + { + Label: "Receive valid image message", + URL: waReceiveURL, + Data: imageMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"msg"`, + ExpectedMsgText: Sp("the caption"), + ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, + ExpectedURN: "whatsapp:250788123123", + ExpectedExternalID: "41", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + }, + { + Label: "Receive valid interactive button message", + URL: waReceiveURL, + Data: interactiveButtonMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"msg"`, + ExpectedMsgText: Sp("BUTTON1"), + ExpectedURN: "whatsapp:250788123123", + ExpectedExternalID: "41", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + }, + { + Label: "Receive valid interactive list message", + URL: waReceiveURL, + Data: interactiveListMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"msg"`, + ExpectedMsgText: Sp("ROW1"), + ExpectedURN: "whatsapp:250788123123", + ExpectedExternalID: "41", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + }, + { + Label: "Receive valid location message", + URL: waReceiveURL, + Data: locationMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"msg"`, + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"geo:0.000000,1.000000"}, + ExpectedURN: "whatsapp:250788123123", + ExpectedExternalID: "41", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + }, + { + Label: "Receive valid video message", + URL: waReceiveURL, + Data: videoMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"msg"`, + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, + ExpectedURN: "whatsapp:250788123123", + ExpectedExternalID: "41", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + }, + { + Label: "Receive valid voice message", + URL: waReceiveURL, + Data: voiceMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"msg"`, + ExpectedMsgText: Sp(""), + ExpectedAttachments: []string{"https://foo.bar/v1/media/41"}, + ExpectedURN: "whatsapp:250788123123", + ExpectedExternalID: "41", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + }, + { + Label: "Receive invalid JSON", + URL: waReceiveURL, + Data: invalidMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "unable to parse", + }, + { + Label: "Receive invalid from", + URL: waReceiveURL, + Data: invalidFrom, + ExpectedRespStatus: 200, + ExpectedBodyContains: "invalid whatsapp id", + }, + { + Label: "Receive invalid timestamp", + URL: waReceiveURL, + Data: invalidTimestamp, + ExpectedRespStatus: 200, + ExpectedBodyContains: "invalid timestamp", + }, + + { + Label: "Receive valid status", + URL: waReceiveURL, + Data: validStatus, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"status"`, + ExpectedMsgStatus: "S", + ExpectedExternalID: "9712A34B4A8B6AD50F", + }, + { + Label: "Receive invalid JSON", + URL: waReceiveURL, + Data: "not json", + ExpectedRespStatus: 200, + ExpectedBodyContains: "unable to parse", + }, + { + Label: "Receive invalid status", + URL: waReceiveURL, + Data: invalidStatus, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"unknown status: in_orbit"`, + }, + { + Label: "Receive ignore status", + URL: waReceiveURL, + Data: ignoreStatus, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"ignoring status: deleted"`, + }, } func TestBuildMediaRequest(t *testing.T) { From 349258556514878988924db66adf7268ff07fe40 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 19 Oct 2022 09:10:04 -0500 Subject: [PATCH 244/294] Don't try to download whatsapp attachments with no mediaID --- handlers/whatsapp/whatsapp.go | 5 +++++ handlers/whatsapp/whatsapp_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index 18fcb1705..891d4fd92 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -299,6 +299,11 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } func resolveMediaURL(channel courier.Channel, mediaID string) (string, error) { + // sometimes WA will send an attachment with status=undownloaded and no ID + if mediaID == "" { + return "", nil + } + urlStr := channel.StringConfigForKey(courier.ConfigBaseURL, "") url, err := url.Parse(urlStr) if err != nil { diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index d51169e31..9625e4bea 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -129,6 +129,22 @@ var documentMsg = `{ }] }` +var documentMsgMissingFile = `{ + "messages": [{ + "from": "250788123123", + "id": "41", + "timestamp": "1454119029", + "type": "document", + "document": { + "mime_type": "text/plain", + "sha256": "the-sha-signature", + "caption": "the caption", + "filename": "filename.type", + "status": "undownloaded" + } + }] +}` + var imageMsg = `{ "messages": [{ "from": "250788123123", @@ -420,6 +436,18 @@ var waTestCases = []ChannelHandleTestCase{ ExpectedExternalID: "41", ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), }, + { + Label: "Receive document message with missing file", + URL: waReceiveURL, + Data: documentMsgMissingFile, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"msg"`, + ExpectedMsgText: Sp("the caption"), + ExpectedAttachments: []string{}, + ExpectedURN: "whatsapp:250788123123", + ExpectedExternalID: "41", + ExpectedDate: time.Date(2016, 1, 30, 1, 57, 9, 0, time.UTC), + }, { Label: "Receive invalid JSON", URL: waReceiveURL, From ec16e7ae2cb8ae42c727cd5816e23507422e849a Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 19 Oct 2022 09:28:12 -0500 Subject: [PATCH 245/294] Update CHANGELOG.md for v7.5.51 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fafa43dc5..1eecb1f3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.51 +---------- + * Don't try to download WA attachments with no mediaID + * Add WAC interactive message support with attachments, quick replies and captions. + v7.5.50 ---------- * Fix recording overall time of an attachment-fetch channel log From 1cc1ab7934c7cc75ca8ae643e8973ced66e45093 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 19 Oct 2022 16:33:59 +0200 Subject: [PATCH 246/294] Add support for JustCall channel type --- cmd/courier/main.go | 1 + handlers/justcall/justcall.go | 239 +++++++++++++++++++++ handlers/justcall/justcall_test.go | 329 +++++++++++++++++++++++++++++ 3 files changed, 569 insertions(+) create mode 100644 handlers/justcall/justcall.go create mode 100644 handlers/justcall/justcall_test.go diff --git a/cmd/courier/main.go b/cmd/courier/main.go index 3ed69adb7..2d11f1df9 100644 --- a/cmd/courier/main.go +++ b/cmd/courier/main.go @@ -37,6 +37,7 @@ import ( _ "github.com/nyaruka/courier/handlers/jasmin" _ "github.com/nyaruka/courier/handlers/jiochat" _ "github.com/nyaruka/courier/handlers/junebug" + _ "github.com/nyaruka/courier/handlers/justcall" _ "github.com/nyaruka/courier/handlers/kaleyra" _ "github.com/nyaruka/courier/handlers/kannel" _ "github.com/nyaruka/courier/handlers/line" diff --git a/handlers/justcall/justcall.go b/handlers/justcall/justcall.go new file mode 100644 index 000000000..a293063c8 --- /dev/null +++ b/handlers/justcall/justcall.go @@ -0,0 +1,239 @@ +package justcall + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "net/http" + "strings" + "time" + + "github.com/buger/jsonparser" + "github.com/nyaruka/courier" + "github.com/nyaruka/courier/handlers" +) + +var ( + sendURL = "https://api.justcall.io/v1/texts/new" + maxMsgLength = 160 +) + +type handler struct { + handlers.BaseHandler +} + +func newHandler() courier.ChannelHandler { + return &handler{handlers.NewBaseHandler(courier.ChannelType("JCL"), "JustCall")} +} + +func init() { + courier.RegisterHandler(newHandler()) +} + +// Initialize implements courier.ChannelHandler +func (h *handler) Initialize(s courier.Server) error { + h.SetServer(s) + s.AddHandlerRoute(h, http.MethodPost, "receive", h.receiveMessage) + s.AddHandlerRoute(h, http.MethodPost, "status", h.statusMessage) + return nil +} + +// { +// "data": { +// "type": "sms", +// "direction": "0", +// "justcall_number": "192XXXXXXXX", +// "contact_name": "Sushant Tripathi", +// "contact_number": "+91810XXXXXXX", +// "contact_email": "customer@gmail.com", +// "is_contact": 1, +// "content": "Hey !", +// "signature": "35e89fc56b497xxxxxxxxxx8f7b27fe49d", +// "datetime": "2020-12-03 13:35:13", +// "delivery_status": "sent", +// "requestid": "1229153", +// "messageid": 26523491, +// "is_mms": "1", +// "mms": [ +// { +// "media_url": "https://www.filepicker.io/api/file/p6j9ExQNWMCCYOQvHI", +// "content_type": "image/jpeg" +// }, +// { +// "media_url": "https://www.filepicker.io/api/file/axNH43SFm7inN3iKDz", +// "content_type": "image/png" +// }, +// { +// "media_url": "https://www.filepicker.io/api//file/cN95JZSM2ScSXGamlh", +// "content_type": "image/jpeg" +// } +// ] , +// "agent_name": "Sales JustCall", +// "agent_id": 10636 +// } +// } +type moPayload struct { + Data struct { + Type string `json:"type"` + Direction string `json:"direction"` + To string `json:"justcall_number"` + From string `json:"contact_number"` + Name string `json:"contact_name"` + Content string `json:"content"` + Datetime string `json:"datetime"` + Status string `json:"delivery_status"` + MessageID int32 `json:"messageid"` + MMS []struct { + MediaURL string `json:"media_url"` + ContentType string `json:"content_type"` + } `json:"mms"` + } `json:"data"` +} + +func (h *handler) receiveMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { + payload := &moPayload{} + err := handlers.DecodeAndValidateJSON(payload, r) + if err != nil { + return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, err) + } + + if payload.Data.Type != "sms" || payload.Data.Direction != "I" { + return nil, handlers.WriteAndLogRequestIgnored(ctx, h, c, w, r, "Ignoring request, no message") + } + + dateString := payload.Data.Datetime + date := time.Now() + if dateString != "" { + date, err = time.Parse("2006-01-02 15:04:05", dateString) + if err != nil { + return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, errors.New("invalid date format, must be RFC 3339")) + } + date = date.UTC() + } + + urn, err := handlers.StrictTelForCountry(payload.Data.From, c.Country()) + if err != nil { + return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, err) + } + + // build our msg + msg := h.Backend().NewIncomingMsg(c, urn, payload.Data.Content, clog).WithExternalID(fmt.Sprint(payload.Data.MessageID)).WithReceivedOn(date) + + if len(payload.Data.MMS) > 0 { + msg.WithAttachment(payload.Data.MMS[0].MediaURL) + } + + // and finally write our message + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) +} + +var statusMapping = map[string]courier.MsgStatusValue{ + "delivered": courier.MsgDelivered, + "sent": courier.MsgSent, + "undelivered": courier.MsgErrored, + "failed": courier.MsgFailed, +} + +func (h *handler) statusMessage(ctx context.Context, c courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { + payload := &moPayload{} + err := handlers.DecodeAndValidateJSON(payload, r) + if err != nil { + return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, err) + } + + if payload.Data.Type != "sms" || payload.Data.Direction != "O" { + return nil, handlers.WriteAndLogRequestIgnored(ctx, h, c, w, r, "Ignoring request, no message") + } + + msgStatus, found := statusMapping[payload.Data.Status] + if !found { + return nil, handlers.WriteAndLogRequestError(ctx, h, c, w, r, fmt.Errorf("unknown status '%s', must be one of send, delivered, undelivered, failed", payload.Data.Status)) + } + // write our status + status := h.Backend().NewMsgStatusForExternalID(c, fmt.Sprint(payload.Data.MessageID), msgStatus, clog) + return handlers.WriteMsgStatusAndResponse(ctx, h, c, status, w, r) +} + +type mtPayload struct { + From string `json:"from"` + To string `json:"to"` + Body string `json:"body"` + MediaURL string `json:"media_url,omitempty"` +} + +// Send implements courier.ChannelHandler +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { + apiKey := msg.Channel().StringConfigForKey(courier.ConfigAPIKey, "") + if apiKey == "" { + return nil, fmt.Errorf("no API key set for JCL channel") + } + + apiSecret := msg.Channel().StringConfigForKey(courier.ConfigSecret, "") + if apiSecret == "" { + return nil, fmt.Errorf("no API secret set for JCL channel") + } + + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) + mediaURLs := make([]string, 0, 5) + text := msg.Text() + + if len(msg.Attachments()) <= 5 { + for _, a := range msg.Attachments() { + _, url := handlers.SplitAttachment(a) + mediaURLs = append(mediaURLs, url) + } + } else { + text = handlers.GetTextAndAttachments(msg) + } + + payload := mtPayload{From: msg.Channel().Address(), To: msg.URN().Path(), Body: text} + if len(mediaURLs) > 0 { + payload.MediaURL = strings.Join(mediaURLs, ",") + } + + jsonPayload, err := json.Marshal(payload) + if err != nil { + return nil, err + } + + req, err := http.NewRequest(http.MethodPost, sendURL, bytes.NewReader(jsonPayload)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") + req.Header.Set("Authorization", fmt.Sprintf("%s:%s", apiKey, apiSecret)) + + resp, respBody, err := handlers.RequestHTTP(req, clog) + if err != nil || resp.StatusCode/100 != 2 { + return status, nil + } + + respStatus, err := jsonparser.GetString(respBody, "status") + if err != nil { + clog.Error(courier.ErrorResponseValueMissing("status")) + clog.End() + return status, h.Backend().WriteChannelLog(ctx, clog) + } + if respStatus != "success" { + return status, nil + + } + + externalID, err := jsonparser.GetInt(respBody, "id") + if err != nil { + clog.Error(courier.ErrorResponseValueMissing("id")) + clog.End() + return status, h.Backend().WriteChannelLog(ctx, clog) + } + + if externalID != 0 { + status.SetExternalID(fmt.Sprintf("%d", externalID)) + } + + status.SetStatus(courier.MsgWired) + return status, nil + +} diff --git a/handlers/justcall/justcall_test.go b/handlers/justcall/justcall_test.go new file mode 100644 index 000000000..de13f08b8 --- /dev/null +++ b/handlers/justcall/justcall_test.go @@ -0,0 +1,329 @@ +package justcall + +import ( + "net/http/httptest" + "testing" + "time" + + "github.com/nyaruka/courier" + . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" +) + +var testChannels = []courier.Channel{ + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JCL", "2020", "US", map[string]interface{}{courier.ConfigAPIKey: "api_key", courier.ConfigSecret: "api_secret"}), +} + +var ( + receiveURL = "/c/jcl/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive" + statusURL = "/c/jcl/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status" +) + +var helloMsg = `{ + "data": { + "type": "sms", + "direction": "I", + "justcall_number": "2020", + "contact_name": "Sushant Tripathi", + "contact_number": "+385916242493", + "contact_email": "customer@gmail.com", + "is_contact": 1, + "content": "Hello there", + "signature": "35e89fc56b497xxxxxxxxxx8f7b27fe49d", + "datetime": "2020-12-03 13:35:13", + "delivery_status": "sent", + "requestid": "1229153", + "messageid": 26523491, + "is_mms": "0", + "mms": [], + "agent_name": "Sales JustCall", + "agent_id": 10636 + } +}` + +var wrongMsgDirection = `{ + "data": { + "type": "sms", + "direction": "O", + "justcall_number": "2020", + "contact_name": "Sushant Tripathi", + "contact_number": "+385916242493", + "contact_email": "customer@gmail.com", + "is_contact": 1, + "content": "Hello there", + "signature": "35e89fc56b497xxxxxxxxxx8f7b27fe49d", + "datetime": "2020-12-03 13:35:13", + "delivery_status": "sent", + "requestid": "1229153", + "messageid": 26523491, + "is_mms": "0", + "mms": [], + "agent_name": "Sales JustCall", + "agent_id": 10636 + } +}` + +var emptyMsg = `{ + "data": { + "type": "sms", + "direction": "I", + "justcall_number": "2020", + "contact_name": "Sushant Tripathi", + "contact_number": "+385916242493", + "contact_email": "customer@gmail.com", + "is_contact": 1, + "content": "", + "signature": "35e89fc56b497xxxxxxxxxx8f7b27fe49d", + "datetime": "2020-12-03 13:35:13", + "delivery_status": "sent", + "requestid": "1229153", + "messageid": 26523491, + "is_mms": "0", + "mms": [], + "agent_name": "Sales JustCall", + "agent_id": 10636 + } +}` + +var attachmeentMsg = `{ + "data": { + "type": "sms", + "direction": "I", + "justcall_number": "2020", + "contact_name": "Sushant Tripathi", + "contact_number": "+385916242493", + "contact_email": "customer@gmail.com", + "is_contact": 1, + "content": "Hello there", + "signature": "35e89fc56b497xxxxxxxxxx8f7b27fe49d", + "datetime": "2020-12-03 13:35:13", + "delivery_status": "sent", + "requestid": "1229153", + "messageid": 26523491, + "is_mms": "1", + "mms": [ + { + "media_url": "https://foo.bar/attachmentURL_Image", + "content_type": "image/jpeg" + } + ], + "agent_name": "Sales JustCall", + "agent_id": 10636 + } +}` + +var validStatus = `{ + "data": { + "type": "sms", + "direction": "O", + "justcall_number": "2020", + "contact_name": "Sushant Tripathi", + "contact_number": "+385916242493", + "contact_email": "customer@gmail.com", + "is_contact": 1, + "content": "Hello there", + "signature": "35e89fc56b497xxxxxxxxxx8f7b27fe49d", + "datetime": "2020-12-03 13:35:13", + "delivery_status": "sent", + "requestid": "1229153", + "messageid": 26523491, + "is_mms": "1", + "mms": [ + { + "media_url": "https://foo.bar/attachmentURL_Image", + "content_type": "image/jpeg" + } + ], + "agent_name": "Sales JustCall", + "agent_id": 10636 + } +}` + +var invalidStatusDirection = `{ + "data": { + "type": "sms", + "direction": "I", + "justcall_number": "2020", + "contact_name": "Sushant Tripathi", + "contact_number": "+385916242493", + "contact_email": "customer@gmail.com", + "is_contact": 1, + "content": "Hello there", + "signature": "35e89fc56b497xxxxxxxxxx8f7b27fe49d", + "datetime": "2020-12-03 13:35:13", + "delivery_status": "sent", + "requestid": "1229153", + "messageid": 26523491, + "is_mms": "1", + "mms": [ + { + "media_url": "https://foo.bar/attachmentURL_Image", + "content_type": "image/jpeg" + } + ], + "agent_name": "Sales JustCall", + "agent_id": 10636 + } +}` + +var unknownStatus = `{ + "data": { + "type": "sms", + "direction": "O", + "justcall_number": "2020", + "contact_name": "Sushant Tripathi", + "contact_number": "+385916242493", + "contact_email": "customer@gmail.com", + "is_contact": 1, + "content": "Hello there", + "signature": "35e89fc56b497xxxxxxxxxx8f7b27fe49d", + "datetime": "2020-12-03 13:35:13", + "delivery_status": "foo", + "requestid": "1229153", + "messageid": 26523491, + "is_mms": "1", + "mms": [ + { + "media_url": "https://foo.bar/attachmentURL_Image", + "content_type": "image/jpeg" + } + ], + "agent_name": "Sales JustCall", + "agent_id": 10636 + } +}` + +var testCases = []ChannelHandleTestCase{ + { + Label: "Receive Valid Message", + URL: receiveURL, + Data: helloMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Hello there"), + ExpectedURN: "tel:+385916242493", + ExpectedExternalID: "26523491", + ExpectedDate: time.Date(2020, 12, 03, 13, 35, 13, 000000000, time.FixedZone("", 0)), + }, + { + Label: "Receive Wrong Message Direction", + URL: receiveURL, + Data: wrongMsgDirection, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Ignored", + }, + { + Label: "Receive Empty Message", + URL: receiveURL, + Data: emptyMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp(""), + ExpectedURN: "tel:+385916242493", + ExpectedExternalID: "26523491", + ExpectedDate: time.Date(2020, 12, 03, 13, 35, 13, 000000000, time.FixedZone("", 0)), + }, + { + Label: "Receive Attachment Message", + URL: receiveURL, + Data: attachmeentMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Hello there"), + ExpectedAttachments: []string{"https://foo.bar/attachmentURL_Image"}, + ExpectedURN: "tel:+385916242493", + ExpectedExternalID: "26523491", + ExpectedDate: time.Date(2020, 12, 03, 13, 35, 13, 000000000, time.FixedZone("", 0)), + }, + { + Label: "Receive valid status ", + URL: statusURL, + Data: validStatus, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"status"`, + ExpectedMsgStatus: "S", + ExpectedExternalID: "26523491", + }, + { + Label: "Receive invalid status direction", + URL: statusURL, + Data: invalidStatusDirection, + ExpectedRespStatus: 200, + ExpectedBodyContains: `Ignored`, + }, + { + Label: "Receive unknown status direction", + URL: statusURL, + Data: unknownStatus, + ExpectedRespStatus: 400, + ExpectedBodyContains: `unknown status 'foo', must be one of send, delivered, undelivered, failed`, + }, +} + +func TestHandler(t *testing.T) { + RunChannelTestCases(t, testChannels, newHandler(), testCases) +} + +func BenchmarkHandler(b *testing.B) { + RunChannelBenchmarks(b, testChannels, newHandler(), testCases) +} + +// setSend takes care of setting the sendURL to call +func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { + sendURL = s.URL +} + +var defaultSendTestCases = []ChannelSendTestCase{ + { + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponseBody: `{"status":"success","message":"Text sent","id":12345}`, + MockResponseStatus: 200, + ExpectedHeaders: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "api_key:api_secret", + }, + ExpectedRequestBody: `{"from":"2020","to":"+250788383383","body":"Simple Message"}`, + ExpectedMsgStatus: "W", + ExpectedExternalID: "12345", + SendPrep: setSendURL, + }, + { + Label: "Send Document", + MsgText: "This is some text.", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, + MockResponseBody: `{"status":"success","message":"Text sent","id":12345}`, + MockResponseStatus: 200, + ExpectedRequestBody: `{"from":"2020","to":"+250788383383","body":"This is some text.","media_url":"https://foo.bar/document.pdf"}`, + ExpectedMsgStatus: "W", + ExpectedExternalID: "12345", + SendPrep: setSendURL}, + { + Label: "ID Error", + MsgText: "ID Error", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "status": "success" }`, + MockResponseStatus: 200, + ExpectedMsgStatus: "E", + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("id")}, + SendPrep: setSendURL, + }, + { + Label: "Error", + MsgText: "Error", + MsgURN: "tel:+250788383383", + MockResponseBody: `{ "status": "fail" }`, + MockResponseStatus: 403, + ExpectedMsgStatus: "E", + SendPrep: setSendURL, + }, +} + +func TestSending(t *testing.T) { + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JCL", "2020", "US", map[string]interface{}{courier.ConfigAPIKey: "api_key", courier.ConfigSecret: "api_secret"}) + + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"api_key", "api_secret"}, nil) +} From 4d46fe201351e43f28da4a30228fc1a4e97519c4 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 19 Oct 2022 16:57:12 +0200 Subject: [PATCH 247/294] Adjust to use jsonx.MustMarshal --- handlers/justcall/justcall.go | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/handlers/justcall/justcall.go b/handlers/justcall/justcall.go index a293063c8..066f6c531 100644 --- a/handlers/justcall/justcall.go +++ b/handlers/justcall/justcall.go @@ -3,7 +3,6 @@ package justcall import ( "bytes" "context" - "encoding/json" "errors" "fmt" "net/http" @@ -13,6 +12,7 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/gocommon/jsonx" ) var ( @@ -193,12 +193,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann payload.MediaURL = strings.Join(mediaURLs, ",") } - jsonPayload, err := json.Marshal(payload) - if err != nil { - return nil, err - } - - req, err := http.NewRequest(http.MethodPost, sendURL, bytes.NewReader(jsonPayload)) + req, err := http.NewRequest(http.MethodPost, sendURL, bytes.NewReader(jsonx.MustMarshal(payload))) if err != nil { return nil, err } @@ -214,7 +209,6 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann respStatus, err := jsonparser.GetString(respBody, "status") if err != nil { clog.Error(courier.ErrorResponseValueMissing("status")) - clog.End() return status, h.Backend().WriteChannelLog(ctx, clog) } if respStatus != "success" { @@ -225,7 +219,6 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann externalID, err := jsonparser.GetInt(respBody, "id") if err != nil { clog.Error(courier.ErrorResponseValueMissing("id")) - clog.End() return status, h.Backend().WriteChannelLog(ctx, clog) } From b89ac28e510b98a5954fb451d46a9c297002d7a6 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 19 Oct 2022 10:09:02 -0500 Subject: [PATCH 248/294] Update CHANGELOG.md for v7.5.52 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1eecb1f3a..c108e76a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.52 +---------- + * Add support for JustCall channel type + v7.5.51 ---------- * Don't try to download WA attachments with no mediaID From 2a933e5d9ec9c0763325060f1bd6a8f52cf658f3 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 25 Oct 2022 10:29:47 -0500 Subject: [PATCH 249/294] Test against redis 6.2 and postgres 14 --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c258736d3..fabc85152 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,13 +2,13 @@ name: CI on: [push, pull_request] env: go-version: "1.19.x" - redis-version: "5.0.6" jobs: test: name: Test strategy: matrix: - pg-version: ["12", "13"] + redis-version: ["5.0.6", "6.2"] + pg-version: ["13", "14"] runs-on: ubuntu-latest steps: - name: Checkout code @@ -17,7 +17,7 @@ jobs: - name: Install Redis uses: zhulik/redis-action@v1.0.0 with: - redis version: ${{ env.redis-version }} + redis version: ${{ matrix.redis-version }} - name: Install PostgreSQL uses: harmon758/postgresql-action@v1 From 64e19b1aa530b0a7f98cad72a931dbda6da8e505 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 25 Oct 2022 14:12:45 -0500 Subject: [PATCH 250/294] Use redisx.IntervalHash for message de-duping checks --- backends/rapidpro/backend.go | 14 ++-- backends/rapidpro/msg.go | 126 ++++++++--------------------------- 2 files changed, 39 insertions(+), 101 deletions(-) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 9a70fc35d..33a3b0f0d 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -145,7 +145,7 @@ func (b *backend) NewIncomingMsg(channel courier.Channel, urn urns.URN, text str msg.WithReceivedOn(time.Now().UTC()) // have we seen this msg in the past period? - prevUUID := checkMsgSeen(b, msg) + prevUUID := b.checkMsgSeen(msg) if prevUUID != courier.NilMsgUUID { // if so, use its UUID and that we've been written msg.UUID_ = prevUUID @@ -182,7 +182,7 @@ func (b *backend) PopNextOutgoingMsg(ctx context.Context) (courier.Msg, error) { dbMsg.workerToken = token // clear out our seen incoming messages - clearMsgSeen(rc, dbMsg) + b.clearMsgSeen(rc, dbMsg) return dbMsg, nil } @@ -392,8 +392,8 @@ func (b *backend) WriteChannelLog(ctx context.Context, clog *courier.ChannelLog) // Check if external ID has been seen in a period func (b *backend) CheckExternalIDSeen(msg courier.Msg) courier.Msg { - var prevUUID = checkExternalIDSeen(b, msg) m := msg.(*DBMsg) + var prevUUID = b.checkExternalIDSeen(m) if prevUUID != courier.NilMsgUUID { // if so, use its UUID and that we've been written m.UUID_ = prevUUID @@ -404,7 +404,7 @@ func (b *backend) CheckExternalIDSeen(msg courier.Msg) courier.Msg { // Mark a external ID as seen for a period func (b *backend) WriteExternalIDSeen(msg courier.Msg) { - writeExternalIDSeen(b, msg) + b.writeExternalIDSeen(msg.(*DBMsg)) } // SaveAttachment saves an attachment to backend storage @@ -871,6 +871,9 @@ func newBackend(cfg *courier.Config) courier.Backend { mediaCache: redisx.NewIntervalHash("media-lookups", time.Hour*24, 2), mediaMutexes: *syncx.NewHashMutex(8), + + seenMsgs: redisx.NewIntervalHash("seen-msgs", time.Second*2, 2), + seenExternalIDs: redisx.NewIntervalHash("seen-external-ids", time.Hour*24, 2), } } @@ -891,6 +894,9 @@ type backend struct { mediaCache *redisx.IntervalHash mediaMutexes syncx.HashMutex + seenMsgs *redisx.IntervalHash + seenExternalIDs *redisx.IntervalHash + // both sqlx and redis provide wait stats which are cummulative that we need to convert into increments dbWaitDuration time.Duration dbWaitCount int64 diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index 6814efa66..cf456173c 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -94,7 +94,7 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch err = courier.WriteToSpool(b.config.SpoolDir, "msgs", m) } // mark this msg as having been seen - writeMsgSeen(b, m) + b.writeMsgSeen(m) return err } @@ -260,134 +260,63 @@ func (b *backend) flushMsgFile(filename string, contents []byte) error { // Deduping utility methods //----------------------------------------------------------------------------- -var luaMsgSeen = redis.NewScript(3, `-- KEYS: [Window, PrevWindow, URNFingerprint] - -- try to look up in window - local found = redis.call("hget", KEYS[1], KEYS[3]) - - -- didn't find it, try in our previous window - if not found then - found = redis.call("hget", KEYS[2], KEYS[3]) - end - - -- return the fingerprint found - return found -`) - // checkMsgSeen tries to look up whether a msg with the fingerprint passed in was seen in window or prevWindow. If // found returns the UUID of that msg, if not returns empty string -func checkMsgSeen(b *backend, msg *DBMsg) courier.MsgUUID { - r := b.redisPool.Get() - defer r.Close() - - urnFingerprint := msg.urnFingerprint() - - now := time.Now().In(time.UTC) - prev := now.Add(time.Second * -2) - windowKey := fmt.Sprintf("seen:msgs:%s:%02d", now.Format("2006-01-02-15:04"), now.Second()/2*2) - prevWindowKey := fmt.Sprintf("seen:msgs:%s:%02d", prev.Format("2006-01-02-15:04"), prev.Second()/2*2) +func (b *backend) checkMsgSeen(msg *DBMsg) courier.MsgUUID { + rc := b.redisPool.Get() + defer rc.Close() - // see if there were any messages received in the past 4 seconds - found, _ := redis.String(luaMsgSeen.Do(r, windowKey, prevWindowKey, urnFingerprint)) + uuidAndText, _ := b.seenMsgs.Get(rc, msg.fingerprint(false)) // if so, test whether the text it the same - if found != "" { - prevText := found[37:] + if uuidAndText != "" { + prevText := uuidAndText[37:] // if it is the same, return the UUID if prevText == msg.Text() { - return courier.NewMsgUUIDFromString(found[:36]) + return courier.NewMsgUUIDFromString(uuidAndText[:36]) } } return courier.NilMsgUUID } -var luaWriteMsgSeen = redis.NewScript(3, `-- KEYS: [Window, URNFingerprint, UUIDText] - redis.call("hset", KEYS[1], KEYS[2], KEYS[3]) - redis.call("expire", KEYS[1], 5) -`) - // writeMsgSeen writes that the message with the passed in fingerprint and UUID was seen in the // passed in window -func writeMsgSeen(b *backend, msg *DBMsg) { - r := b.redisPool.Get() - defer r.Close() - - urnFingerprint := msg.urnFingerprint() - uuidText := fmt.Sprintf("%s|%s", msg.UUID().String(), msg.Text_) - now := time.Now().In(time.UTC) - windowKey := fmt.Sprintf("seen:msgs:%s:%02d", now.Format("2006-01-02-15:04"), now.Second()/2*2) +func (b *backend) writeMsgSeen(msg *DBMsg) { + rc := b.redisPool.Get() + defer rc.Close() - luaWriteMsgSeen.Do(r, windowKey, urnFingerprint, uuidText) + b.seenMsgs.Set(rc, msg.fingerprint(false), fmt.Sprintf("%s|%s", msg.UUID().String(), msg.Text())) } // clearMsgSeen clears our seen incoming messages for the passed in channel and URN -func clearMsgSeen(rc redis.Conn, msg *DBMsg) { - urnFingerprint := msg.urnFingerprint() - - now := time.Now().In(time.UTC) - prev := now.Add(time.Second * -2) - windowKey := fmt.Sprintf("seen:msgs:%s:%02d", now.Format("2006-01-02-15:04"), now.Second()/2*2) - prevWindowKey := fmt.Sprintf("seen:msgs:%s:%02d", prev.Format("2006-01-02-15:04"), prev.Second()/2*2) - - rc.Send("hdel", windowKey, urnFingerprint) - rc.Do("hdel", prevWindowKey, urnFingerprint) +func (b *backend) clearMsgSeen(rc redis.Conn, msg *DBMsg) { + b.seenMsgs.Remove(rc, msg.fingerprint(false)) } -var luaExternalIDSeen = redis.NewScript(3, `-- KEYS: [Window, PrevWindow, ExternalID] - -- try to look up in window - local found = redis.call("hget", KEYS[1], KEYS[3]) - - -- didn't find it, try in our previous window - if not found then - found = redis.call("hget", KEYS[2], KEYS[3]) - end - - -- return the fingerprint found - return found -`) - -func checkExternalIDSeen(b *backend, msg courier.Msg) courier.MsgUUID { - r := b.redisPool.Get() - defer r.Close() - - urnFingerprint := fmt.Sprintf("%s:%s|%s", msg.Channel().UUID(), msg.URN().Identity(), msg.ExternalID()) - - now := time.Now().In(time.UTC) - prev := now.Add(time.Hour * -24) - windowKey := fmt.Sprintf("seen:externalid:%s", now.Format("2006-01-02")) - prevWindowKey := fmt.Sprintf("seen:externalid:%s", prev.Format("2006-01-02")) +func (b *backend) checkExternalIDSeen(msg *DBMsg) courier.MsgUUID { + rc := b.redisPool.Get() + defer rc.Close() - // see if there were any messages received in the past 24 hours - found, _ := redis.String(luaExternalIDSeen.Do(r, windowKey, prevWindowKey, urnFingerprint)) + uuidAndText, _ := b.seenExternalIDs.Get(rc, msg.fingerprint(true)) // if so, test whether the text it the same - if found != "" { - prevText := found[37:] + if uuidAndText != "" { + prevText := uuidAndText[37:] // if it is the same, return the UUID if prevText == msg.Text() { - return courier.NewMsgUUIDFromString(found[:36]) + return courier.NewMsgUUIDFromString(uuidAndText[:36]) } } return courier.NilMsgUUID } -var luaWriteExternalIDSeen = redis.NewScript(3, `-- KEYS: [Window, ExternalID, Seen] - redis.call("hset", KEYS[1], KEYS[2], KEYS[3]) - redis.call("expire", KEYS[1], 86400) -`) - -func writeExternalIDSeen(b *backend, msg courier.Msg) { - r := b.redisPool.Get() - defer r.Close() - - urnFingerprint := fmt.Sprintf("%s:%s|%s", msg.Channel().UUID(), msg.URN().Identity(), msg.ExternalID()) - uuidText := fmt.Sprintf("%s|%s", msg.UUID().String(), msg.Text()) - - now := time.Now().In(time.UTC) - windowKey := fmt.Sprintf("seen:externalid:%s", now.Format("2006-01-02")) +func (b *backend) writeExternalIDSeen(msg *DBMsg) { + rc := b.redisPool.Get() + defer rc.Close() - luaWriteExternalIDSeen.Do(r, windowKey, urnFingerprint, uuidText) + b.seenExternalIDs.Set(rc, msg.fingerprint(true), fmt.Sprintf("%s|%s", msg.UUID().String(), msg.Text())) } //----------------------------------------------------------------------------- @@ -511,7 +440,10 @@ func (m *DBMsg) Metadata() json.RawMessage { } // fingerprint returns a fingerprint for this msg, suitable for figuring out if this is a dupe -func (m *DBMsg) urnFingerprint() string { +func (m *DBMsg) fingerprint(withExtID bool) string { + if withExtID { + return fmt.Sprintf("%s:%s|%s", m.Channel().UUID(), m.URN().Identity(), m.ExternalID()) + } return fmt.Sprintf("%s:%s", m.ChannelUUID_, m.URN_.Identity()) } From 85c907c55e4ab1293fecf8a6784a47a37e2aef28 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 26 Oct 2022 10:04:02 -0500 Subject: [PATCH 251/294] Update CHANGELOG.md for v7.5.53 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c108e76a1..269ea6af4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.53 +---------- + * Use redisx.IntervalHash for message de-duping checks + v7.5.52 ---------- * Add support for JustCall channel type From a142dbe8d8404e93ee1ac6f4d66168b170c4ba57 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 26 Oct 2022 11:29:52 -0500 Subject: [PATCH 252/294] Fetch access token for JioChat channels as needed --- attachments.go | 2 +- handler.go | 2 +- handlers/facebookapp/facebookapp.go | 2 +- handlers/facebookapp/facebookapp_test.go | 6 +- handlers/jiochat/jiochat.go | 156 ++++++++++++----------- handlers/jiochat/jiochat_test.go | 134 +++++++------------ handlers/line/line.go | 2 +- handlers/line/line_test.go | 2 +- handlers/rocketchat/rocketchat.go | 2 +- handlers/wechat/wechat.go | 2 +- handlers/wechat/wechat_test.go | 2 +- handlers/whatsapp/whatsapp.go | 2 +- handlers/whatsapp/whatsapp_test.go | 6 +- 13 files changed, 137 insertions(+), 183 deletions(-) diff --git a/attachments.go b/attachments.go index 96b53d336..53d74c585 100644 --- a/attachments.go +++ b/attachments.go @@ -77,7 +77,7 @@ func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, at builder, isBuilder := handler.(AttachmentRequestBuilder) if isBuilder { httpClient = builder.AttachmentRequestClient(channel) - attRequest, err = builder.BuildAttachmentRequest(ctx, b, channel, parsedURL.String()) + attRequest, err = builder.BuildAttachmentRequest(ctx, b, channel, parsedURL.String(), clog) } else { httpClient = utils.GetHTTPClient() attRequest, err = http.NewRequest(http.MethodGet, attURL, nil) diff --git a/handler.go b/handler.go index 704604d7e..522fbf6a4 100644 --- a/handler.go +++ b/handler.go @@ -42,7 +42,7 @@ type URNDescriber interface { // AttachmentRequestBuilder is the interface handlers which can allow a custom way to download attachment media for messages should satisfy type AttachmentRequestBuilder interface { - BuildAttachmentRequest(context.Context, Backend, Channel, string) (*http.Request, error) + BuildAttachmentRequest(context.Context, Backend, Channel, string, *ChannelLog) (*http.Request, error) AttachmentRequestClient(Channel) *http.Client } diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 203e79c87..b9d29541b 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -1509,7 +1509,7 @@ func (h *handler) getTemplate(msg courier.Msg) (*MsgTemplating, error) { } // BuildAttachmentRequest to download media for message attachment with Bearer token set -func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { +func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string, clog *courier.ChannelLog) (*http.Request, error) { token := h.Server().Config().WhatsappAdminSystemUserToken if token == "" { return nil, fmt.Errorf("missing token for WAC channel") diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index c7add529a..a17c109e0 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -1417,19 +1417,19 @@ func TestBuildMediaRequest(t *testing.T) { s := newServer(mb) wacHandler := &handler{NewBaseHandlerWithParams(courier.ChannelType("WAC"), "WhatsApp Cloud", false, nil)} wacHandler.Initialize(s) - req, _ := wacHandler.BuildAttachmentRequest(context.Background(), mb, testChannelsWAC[0], "https://example.org/v1/media/41") + req, _ := wacHandler.BuildAttachmentRequest(context.Background(), mb, testChannelsWAC[0], "https://example.org/v1/media/41", nil) assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, "Bearer wac_admin_system_user_token", req.Header.Get("Authorization")) fbaHandler := &handler{NewBaseHandlerWithParams(courier.ChannelType("FBA"), "Facebook", false, nil)} fbaHandler.Initialize(s) - req, _ = fbaHandler.BuildAttachmentRequest(context.Background(), mb, testChannelsFBA[0], "https://example.org/v1/media/41") + req, _ = fbaHandler.BuildAttachmentRequest(context.Background(), mb, testChannelsFBA[0], "https://example.org/v1/media/41", nil) assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, http.Header{}, req.Header) igHandler := &handler{NewBaseHandlerWithParams(courier.ChannelType("IG"), "Instagram", false, nil)} igHandler.Initialize(s) - req, _ = igHandler.BuildAttachmentRequest(context.Background(), mb, testChannelsFBA[0], "https://example.org/v1/media/41") + req, _ = igHandler.BuildAttachmentRequest(context.Background(), mb, testChannelsFBA[0], "https://example.org/v1/media/41", nil) assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, http.Header{}, req.Header) } diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 3f0dcf571..606e9cead 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -6,12 +6,12 @@ import ( "crypto/sha1" "encoding/hex" "encoding/json" - "errors" "fmt" "net/http" "net/url" "sort" "strings" + "sync" "time" "github.com/buger/jsonparser" @@ -21,13 +21,12 @@ import ( "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/jsonx" "github.com/nyaruka/gocommon/urns" - "github.com/sirupsen/logrus" + "github.com/pkg/errors" ) var ( sendURL = "https://channels.jiochat.com" maxMsgLength = 1600 - fetchTimeout = time.Second * 2 ) const ( @@ -41,10 +40,15 @@ func init() { type handler struct { handlers.BaseHandler + + fetchTokenMutex sync.Mutex } func newHandler() courier.ChannelHandler { - return &handler{handlers.NewBaseHandler(courier.ChannelType("JC"), "Jiochat")} + return &handler{ + BaseHandler: handlers.NewBaseHandler(courier.ChannelType("JC"), "Jiochat"), + fetchTokenMutex: sync.Mutex{}, + } } // Initialize is called by the engine once everything is loaded @@ -87,10 +91,6 @@ func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http if encoded == form.Signature { ResponseText = form.EchoStr StatusCode = 200 - go func() { - time.Sleep(fetchTimeout) - h.fetchAccessToken(ctx, channel) - }() } w.Header().Set("Content-Type", "text/plain") @@ -161,71 +161,6 @@ func buildMediaURL(mediaID string) string { return mediaURL.String() } -type fetchPayload struct { - GrantType string `json:"grant_type"` - ClientID string `json:"client_id"` - ClientSecret string `json:"client_secret"` -} - -// fetchAccessToken tries to fetch a new token for our channel, setting the result in redis -func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) error { - clog := courier.NewChannelLog(courier.ChannelLogTypeTokenRefresh, channel, h.RedactValues(channel)) - - tokenURL, _ := url.Parse(fmt.Sprintf("%s/%s", sendURL, "auth/token.action")) - payload := &fetchPayload{ - GrantType: "client_credentials", - ClientID: channel.StringConfigForKey(configAppID, ""), - ClientSecret: channel.StringConfigForKey(configAppSecret, ""), - } - - req, err := http.NewRequest(http.MethodPost, tokenURL.String(), bytes.NewReader(jsonx.MustMarshal(payload))) - if err != nil { - return err - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Accept", "application/json") - - resp, respBody, err := handlers.RequestHTTP(req, clog) - if err != nil || resp.StatusCode/100 != 2 { - clog.End() - return h.Backend().WriteChannelLog(ctx, clog) - } - - accessToken, err := jsonparser.GetString(respBody, "access_token") - if err != nil { - clog.Error(courier.ErrorResponseValueMissing("access_token")) - clog.End() - return h.Backend().WriteChannelLog(ctx, clog) - } - - rc := h.Backend().RedisPool().Get() - defer rc.Close() - - cacheKey := fmt.Sprintf("jiochat_channel_access_token:%s", channel.UUID().String()) - _, err = rc.Do("SET", cacheKey, accessToken, 7200) - - if err != nil { - logrus.WithError(err).Error("error setting the access token to redis") - } - return err -} - -func (h *handler) getAccessToken(channel courier.Channel) (string, error) { - rc := h.Backend().RedisPool().Get() - defer rc.Close() - - cacheKey := fmt.Sprintf("jiochat_channel_access_token:%s", channel.UUID().String()) - accessToken, err := redis.String(rc.Do("GET", cacheKey)) - if err != nil { - return "", err - } - if accessToken == "" { - return "", fmt.Errorf("no access token for channel") - } - - return accessToken, nil -} - type mtPayload struct { MsgType string `json:"msgtype"` ToUser string `json:"touser"` @@ -236,7 +171,7 @@ type mtPayload struct { // Send sends the given message, logging any HTTP calls or errors func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { - accessToken, err := h.getAccessToken(msg.Channel()) + accessToken, err := h.getAccessToken(ctx, msg.Channel(), clog) if err != nil { return nil, err } @@ -271,7 +206,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // DescribeURN handles Jiochat contact details func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLog) (map[string]string, error) { - accessToken, err := h.getAccessToken(channel) + accessToken, err := h.getAccessToken(ctx, channel, clog) if err != nil { return nil, err } @@ -298,13 +233,13 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn } // BuildAttachmentRequest download media for message attachment -func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { +func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string, clog *courier.ChannelLog) (*http.Request, error) { parsedURL, err := url.Parse(attachmentURL) if err != nil { return nil, err } - accessToken, err := h.getAccessToken(channel) + accessToken, err := h.getAccessToken(ctx, channel, clog) if err != nil { return nil, err } @@ -320,3 +255,70 @@ func (*handler) AttachmentRequestClient(ch courier.Channel) *http.Client { } var _ courier.AttachmentRequestBuilder = (*handler)(nil) + +func (h *handler) getAccessToken(ctx context.Context, channel courier.Channel, clog *courier.ChannelLog) (string, error) { + rc := h.Backend().RedisPool().Get() + defer rc.Close() + + tokenKey := fmt.Sprintf("channel-token:%s", channel.UUID().String()) + + h.fetchTokenMutex.Lock() + defer h.fetchTokenMutex.Unlock() + + token, err := redis.String(rc.Do("GET", tokenKey)) + if err != nil && err != redis.ErrNil { + return "", errors.Wrap(err, "error reading cached access token") + } + + if token != "" { + return token, nil + } + + token, err = h.fetchAccessToken(ctx, channel, clog) + if err != nil { + return "", errors.Wrap(err, "error fetching new access token") + } + + _, err = rc.Do("SET", tokenKey, token, "EX", 7200) + if err != nil { + return "", errors.Wrap(err, "error updating cached access token") + } + + return token, nil +} + +type fetchPayload struct { + GrantType string `json:"grant_type"` + ClientID string `json:"client_id"` + ClientSecret string `json:"client_secret"` +} + +// fetchAccessToken tries to fetch a new token for our channel +func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel, clog *courier.ChannelLog) (string, error) { + tokenURL, _ := url.Parse(fmt.Sprintf("%s/%s", sendURL, "auth/token.action")) + payload := &fetchPayload{ + GrantType: "client_credentials", + ClientID: channel.StringConfigForKey(configAppID, ""), + ClientSecret: channel.StringConfigForKey(configAppSecret, ""), + } + + req, err := http.NewRequest(http.MethodPost, tokenURL.String(), bytes.NewReader(jsonx.MustMarshal(payload))) + if err != nil { + return "", err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") + + resp, respBody, err := handlers.RequestHTTP(req, clog) + if err != nil || resp.StatusCode/100 != 2 { + return "", err + } + + token, err := jsonparser.GetString(respBody, "access_token") + if err != nil { + clog.Error(courier.ErrorResponseValueMissing("access_token")) + return "", err + } + + return token, nil +} diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index 3bf426925..60102ca62 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -4,9 +4,7 @@ import ( "context" "crypto/sha1" "encoding/hex" - "fmt" "io" - "log" "net/http" "net/http/httptest" "net/url" @@ -18,6 +16,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/urns" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" @@ -227,55 +226,6 @@ func BenchmarkHandler(b *testing.B) { RunChannelBenchmarks(b, testChannels, newHandler(), testCases) } -func TestFetchAccessToken(t *testing.T) { - fetchCalled := false - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if strings.HasSuffix(r.URL.Path, "auth/token.action") { - defer r.Body.Close() - // valid token - w.Write([]byte(`{"access_token": "TOKEN"}`)) - } - - // mark that we were called - fetchCalled = true - })) - sendURL = server.URL - fetchTimeout = time.Millisecond - - RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ - { - Label: "Receive Message", - URL: receiveURL, - Data: validMsg, - ExpectedRespStatus: 200, - ExpectedBodyContains: "Accepted", - ExpectedMsgText: Sp("Simple Message"), - ExpectedURN: "jiochat:1234", - }, - { - Label: "Verify URL", - URL: verifyURL, - ExpectedRespStatus: 200, - ExpectedBodyContains: "SUCCESS", - PrepRequest: addValidSignature, - }, - { - Label: "Verify URL Invalid signature", - URL: verifyURL, - ExpectedRespStatus: 400, - ExpectedBodyContains: "unknown request", - PrepRequest: addInvalidSignature}, - }) - - // wait for our fetch to be called - time.Sleep(100 * time.Millisecond) - - if !fetchCalled { - t.Error("fetch access point should have been called") - } - -} - // mocks the call to the Jiochat API func buildMockJCAPI(testCases []ChannelHandleTestCase) *httptest.Server { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -323,17 +273,14 @@ func TestDescribeURN(t *testing.T) { defer JCAPI.Close() mb := test.NewMockBackend() - conn := mb.RedisPool().Get() - _, err := conn.Do("SET", "jiochat_channel_access_token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ACCESS_TOKEN") - if err != nil { - log.Fatal(err) - } - - conn.Close() + // ensure there's a cached access token + rc := mb.RedisPool().Get() + defer rc.Close() + rc.Do("SET", "channel-token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ACCESS_TOKEN") s := newServer(mb) - handler := &handler{NewBaseHandler(courier.ChannelType("JC"), "Jiochat")} + handler := newHandler().(*handler) handler.Initialize(s) clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], handler.RedactValues(testChannels[0])) @@ -353,36 +300,45 @@ func TestDescribeURN(t *testing.T) { AssertChannelLogRedaction(t, clog, []string{"secret"}) } -func TestBuildMediaRequest(t *testing.T) { +func TestBuildAttachmentRequest(t *testing.T) { mb := test.NewMockBackend() - conn := mb.RedisPool().Get() - - _, err := conn.Do("SET", "jiochat_channel_access_token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ACCESS_TOKEN") - if err != nil { - log.Fatal(err) - } - conn.Close() - s := newServer(mb) - handler := &handler{NewBaseHandler(courier.ChannelType("JC"), "Jiochat")} - handler.Initialize(s) + // reset send URL + sendURL = "https://channels.jiochat.com" - tcs := []struct { - url string - authorizationHeader string - }{ - { - fmt.Sprintf("%s/media/download.action?media_id=12", sendURL), - "Bearer ACCESS_TOKEN", + defer httpx.SetRequestor(httpx.DefaultRequestor) + httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ + "https://channels.jiochat.com/auth/token.action": { + httpx.NewMockResponse(http.StatusOK, nil, []byte(`{"access_token": "SESAME"}`)), }, - } + })) - for _, tc := range tcs { - req, _ := handler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], tc.url) - assert.Equal(t, tc.url, req.URL.String()) - assert.Equal(t, tc.authorizationHeader, req.Header.Get("Authorization")) - } + // ensure that we start with no cached token + rc := mb.RedisPool().Get() + defer rc.Close() + rc.Do("DEL", "channel-token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab") + s := newServer(mb) + handler := newHandler().(*handler) + handler.Initialize(s) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], handler.RedactValues(testChannels[0])) + + // check that request has the fetched access token + req, err := handler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], "https://channels.jiochat.com/media/download.action?media_id=12", clog) + assert.NoError(t, err) + assert.Equal(t, "https://channels.jiochat.com/media/download.action?media_id=12", req.URL.String()) + assert.Equal(t, "Bearer SESAME", req.Header.Get("Authorization")) + + // and that we have a log for that request + assert.Len(t, clog.HTTPLogs(), 1) + assert.Equal(t, "https://channels.jiochat.com/auth/token.action", clog.HTTPLogs()[0].URL) + + // check that another request reads token from cache + req, err = handler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], "https://channels.jiochat.com/media/download.action?media_id=13", clog) + assert.NoError(t, err) + assert.Equal(t, "https://channels.jiochat.com/media/download.action?media_id=13", req.URL.String()) + assert.Equal(t, "Bearer SESAME", req.Header.Get("Authorization")) + assert.Len(t, clog.HTTPLogs(), 1) } // setSendURL takes care of setting the sendURL to call @@ -448,14 +404,10 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func setupBackend(mb *test.MockBackend) { - conn := mb.RedisPool().Get() - - _, err := conn.Do("SET", "jiochat_channel_access_token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ACCESS_TOKEN") - if err != nil { - log.Fatal(err) - } - - conn.Close() + // ensure there's a cached access token + rc := mb.RedisPool().Get() + defer rc.Close() + rc.Do("SET", "channel-token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ACCESS_TOKEN") } func TestSending(t *testing.T) { diff --git a/handlers/line/line.go b/handlers/line/line.go index bdc1e3341..91735469f 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -183,7 +183,7 @@ func buildMediaURL(mediaID string) string { } // BuildAttachmentRequest to download media for message attachment with Bearer token set -func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { +func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string, clog *courier.ChannelLog) (*http.Request, error) { token := channel.StringConfigForKey(courier.ConfigAuthToken, "") if token == "" { return nil, fmt.Errorf("missing token for LN channel") diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index a6dd4b46c..1eae62219 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -608,7 +608,7 @@ func TestBuildMediaRequest(t *testing.T) { mb := test.NewMockBackend() lnHandler := &handler{NewBaseHandler(courier.ChannelType("LN"), "Line")} - req, _ := lnHandler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], "https://example.org/v1/media/41") + req, _ := lnHandler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], "https://example.org/v1/media/41", nil) assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, "Bearer the-auth-token", req.Header.Get("Authorization")) } diff --git a/handlers/rocketchat/rocketchat.go b/handlers/rocketchat/rocketchat.go index 1317b5591..ad7c747b2 100644 --- a/handlers/rocketchat/rocketchat.go +++ b/handlers/rocketchat/rocketchat.go @@ -90,7 +90,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } // BuildAttachmentRequest download media for message attachment with RC auth_token/user_id set -func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { +func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string, clog *courier.ChannelLog) (*http.Request, error) { adminAuthToken := channel.StringConfigForKey(configAdminAuthToken, "") adminUserID := channel.StringConfigForKey(configAdminUserID, "") if adminAuthToken == "" || adminUserID == "" { diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index ceff631ad..6d51517ec 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -312,7 +312,7 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn } // BuildAttachmentRequest download media for message attachment -func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { +func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string, clog *courier.ChannelLog) (*http.Request, error) { accessToken, err := h.getAccessToken(channel) if err != nil { return nil, err diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index 798ed062a..e0d6eca95 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -322,7 +322,7 @@ func TestBuildMediaRequest(t *testing.T) { } for _, tc := range tcs { - req, _ := handler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], tc.url) + req, _ := handler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], tc.url, nil) assert.Equal(t, fmt.Sprintf("%s/media/get?access_token=ACCESS_TOKEN&media_id=12", sendURL), req.URL.String()) } diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index 891d4fd92..f2212dcb2 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -319,7 +319,7 @@ func resolveMediaURL(channel courier.Channel, mediaID string) (string, error) { } // BuildAttachmentRequest to download media for message attachment with Bearer token set -func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string) (*http.Request, error) { +func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string, clog *courier.ChannelLog) (*http.Request, error) { token := channel.StringConfigForKey(courier.ConfigAuthToken, "") if token == "" { return nil, fmt.Errorf("missing token for WA channel") diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index 9625e4bea..b2b5c7bdc 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -506,17 +506,17 @@ func TestBuildMediaRequest(t *testing.T) { mb := test.NewMockBackend() waHandler := &handler{NewBaseHandler(courier.ChannelType("WA"), "WhatsApp")} - req, _ := waHandler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], "https://example.org/v1/media/41") + req, _ := waHandler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], "https://example.org/v1/media/41", nil) assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, "Bearer the-auth-token", req.Header.Get("Authorization")) d3Handler := &handler{NewBaseHandler(courier.ChannelType("D3"), "360Dialog")} - req, _ = d3Handler.BuildAttachmentRequest(context.Background(), mb, testChannels[1], "https://example.org/v1/media/41") + req, _ = d3Handler.BuildAttachmentRequest(context.Background(), mb, testChannels[1], "https://example.org/v1/media/41", nil) assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, "the-auth-token", req.Header.Get("D360-API-KEY")) txHandler := &handler{NewBaseHandler(courier.ChannelType("TXW"), "TextIt")} - req, _ = txHandler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], "https://example.org/v1/media/41") + req, _ = txHandler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], "https://example.org/v1/media/41", nil) assert.Equal(t, "https://example.org/v1/media/41", req.URL.String()) assert.Equal(t, "Bearer the-auth-token", req.Header.Get("Authorization")) } From 28145180fab962a49887d4c8a7637d3405bbcc21 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 26 Oct 2022 12:11:23 -0500 Subject: [PATCH 253/294] Implement same on-demand access token fetching for wechat channels --- handlers/jiochat/jiochat.go | 25 +++-- handlers/jiochat/jiochat_test.go | 14 +-- handlers/wechat/wechat.go | 155 ++++++++++++++++--------------- handlers/wechat/wechat_test.go | 138 +++++++++------------------ 4 files changed, 153 insertions(+), 179 deletions(-) diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 606e9cead..8dea6a47e 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -232,6 +232,12 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn return map[string]string{"name": nickname}, nil } +func (h *handler) RedactValues(ch courier.Channel) []string { + return []string{ + ch.StringConfigForKey(configAppSecret, ""), + } +} + // BuildAttachmentRequest download media for message attachment func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string, clog *courier.ChannelLog) (*http.Request, error) { parsedURL, err := url.Parse(attachmentURL) @@ -274,12 +280,12 @@ func (h *handler) getAccessToken(ctx context.Context, channel courier.Channel, c return token, nil } - token, err = h.fetchAccessToken(ctx, channel, clog) + token, expires, err := h.fetchAccessToken(ctx, channel, clog) if err != nil { return "", errors.Wrap(err, "error fetching new access token") } - _, err = rc.Do("SET", tokenKey, token, "EX", 7200) + _, err = rc.Do("SET", tokenKey, token, "EX", int(expires/time.Second)) if err != nil { return "", errors.Wrap(err, "error updating cached access token") } @@ -294,7 +300,7 @@ type fetchPayload struct { } // fetchAccessToken tries to fetch a new token for our channel -func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel, clog *courier.ChannelLog) (string, error) { +func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel, clog *courier.ChannelLog) (string, time.Duration, error) { tokenURL, _ := url.Parse(fmt.Sprintf("%s/%s", sendURL, "auth/token.action")) payload := &fetchPayload{ GrantType: "client_credentials", @@ -304,21 +310,26 @@ func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel, req, err := http.NewRequest(http.MethodPost, tokenURL.String(), bytes.NewReader(jsonx.MustMarshal(payload))) if err != nil { - return "", err + return "", 0, err } req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { - return "", err + return "", 0, err } token, err := jsonparser.GetString(respBody, "access_token") if err != nil { clog.Error(courier.ErrorResponseValueMissing("access_token")) - return "", err + return "", 0, err } - return token, nil + expiration, err := jsonparser.GetInt(respBody, "expires_in") + if err != nil || expiration == 0 { + expiration = 7200 + } + + return token, time.Second * time.Duration(expiration), nil } diff --git a/handlers/jiochat/jiochat_test.go b/handlers/jiochat/jiochat_test.go index 60102ca62..1f87aa95f 100644 --- a/handlers/jiochat/jiochat_test.go +++ b/handlers/jiochat/jiochat_test.go @@ -23,7 +23,7 @@ import ( ) var testChannels = []courier.Channel{ - test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JC", "2020", "US", map[string]interface{}{configAppSecret: "secret", configAppID: "app-id"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JC", "2020", "US", map[string]interface{}{configAppSecret: "secret123", configAppID: "app-id"}), } var ( @@ -99,7 +99,7 @@ func addValidSignature(r *http.Request) { timestamp := t.Format("20060102150405") nonce := "nonce" - stringSlice := []string{"secret", timestamp, nonce} + stringSlice := []string{"secret123", timestamp, nonce} sort.Strings(stringSlice) value := strings.Join(stringSlice, "") @@ -123,7 +123,7 @@ func addInvalidSignature(r *http.Request) { timestamp := t.Format("20060102150405") nonce := "nonce" - stringSlice := []string{"secret", timestamp, nonce} + stringSlice := []string{"secret123", timestamp, nonce} sort.Strings(stringSlice) value := strings.Join(stringSlice, "") @@ -297,7 +297,7 @@ func TestDescribeURN(t *testing.T) { assert.Equal(t, metadata, tc.expectedMetadata) } - AssertChannelLogRedaction(t, clog, []string{"secret"}) + AssertChannelLogRedaction(t, clog, []string{"secret123"}) } func TestBuildAttachmentRequest(t *testing.T) { @@ -339,6 +339,8 @@ func TestBuildAttachmentRequest(t *testing.T) { assert.Equal(t, "https://channels.jiochat.com/media/download.action?media_id=13", req.URL.String()) assert.Equal(t, "Bearer SESAME", req.Header.Get("Authorization")) assert.Len(t, clog.HTTPLogs(), 1) + + AssertChannelLogRedaction(t, clog, []string{"secret123"}) } // setSendURL takes care of setting the sendURL to call @@ -412,7 +414,7 @@ func setupBackend(mb *test.MockBackend) { func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JC", "2020", "US", map[string]interface{}{configAppSecret: "secret", configAppID: "app-id"}) + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JC", "2020", "US", map[string]interface{}{configAppSecret: "secret123", configAppID: "app-id"}) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"secret"}, setupBackend) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"secret123"}, setupBackend) } diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index 6d51517ec..44014c1c1 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -6,12 +6,12 @@ import ( "crypto/sha1" "encoding/hex" "encoding/json" - "errors" "fmt" "net/http" "net/url" "sort" "strings" + "sync" "time" "github.com/buger/jsonparser" @@ -20,13 +20,12 @@ import ( "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" - "github.com/sirupsen/logrus" + "github.com/pkg/errors" ) var ( sendURL = "https://api.weixin.qq.com/cgi-bin" maxMsgLength = 1600 - fetchTimeout = time.Second * 2 ) const ( @@ -40,10 +39,15 @@ func init() { type handler struct { handlers.BaseHandler + + fetchTokenMutex sync.Mutex } func newHandler() courier.ChannelHandler { - return &handler{handlers.NewBaseHandler(courier.ChannelType("WC"), "WeChat")} + return &handler{ + BaseHandler: handlers.NewBaseHandler(courier.ChannelType("WC"), "WeChat"), + fetchTokenMutex: sync.Mutex{}, + } } // Initialize is called by the engine once everything is loaded @@ -84,10 +88,6 @@ func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http if encoded == form.Signature { ResponseText = form.EchoStr StatusCode = 200 - go func() { - time.Sleep(fetchTimeout) - h.fetchAccessToken(ctx, channel) - }() } w.Header().Set("Content-Type", "text/plain") @@ -96,68 +96,6 @@ func (h *handler) VerifyURL(ctx context.Context, channel courier.Channel, w http return nil, err } -// fetchAccessToken tries to fetch a new token for our channel, setting the result in redis -func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel) error { - clog := courier.NewChannelLog(courier.ChannelLogTypeTokenRefresh, channel, h.RedactValues(channel)) - - form := url.Values{ - "grant_type": []string{"client_credential"}, - "appid": []string{channel.StringConfigForKey(configAppID, "")}, - "secret": []string{channel.StringConfigForKey(configAppSecret, "")}, - } - tokenURL, _ := url.Parse(fmt.Sprintf("%s/%s", sendURL, "token")) - tokenURL.RawQuery = form.Encode() - - req, _ := http.NewRequest(http.MethodGet, tokenURL.String(), nil) - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - req.Header.Set("Accept", "application/json") - - resp, respBody, err := handlers.RequestHTTP(req, clog) - if err != nil || resp.StatusCode/100 != 2 { - clog.End() - return h.Backend().WriteChannelLog(ctx, clog) - } - - accessToken, err := jsonparser.GetString(respBody, "access_token") - if err != nil { - clog.Error(courier.ErrorResponseValueMissing("access_token")) - clog.End() - return h.Backend().WriteChannelLog(ctx, clog) - } - - expiration, err := jsonparser.GetInt(respBody, "expires_in") - if err != nil { - expiration = 7200 - } - - rc := h.Backend().RedisPool().Get() - defer rc.Close() - - cacheKey := fmt.Sprintf("wechat_channel_access_token:%s", channel.UUID().String()) - _, err = rc.Do("SET", cacheKey, accessToken, expiration) - - if err != nil { - logrus.WithError(err).Error("error setting the access token to redis") - } - return err -} - -func (h *handler) getAccessToken(channel courier.Channel) (string, error) { - rc := h.Backend().RedisPool().Get() - defer rc.Close() - - cacheKey := fmt.Sprintf("wechat_channel_access_token:%s", channel.UUID().String()) - accessToken, err := redis.String(rc.Do("GET", cacheKey)) - if err != nil { - return "", err - } - if accessToken == "" { - return "", fmt.Errorf("no access token for channel") - } - - return accessToken, nil -} - type moPayload struct { FromUsername string `xml:"FromUserName" validate:"required"` MsgType string `xml:"MsgType" validate:"required"` @@ -237,7 +175,7 @@ type mtPayload struct { // Send sends the given message, logging any HTTP calls or errors func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { - accessToken, err := h.getAccessToken(msg.Channel()) + accessToken, err := h.getAccessToken(ctx, msg.Channel(), clog) if err != nil { return nil, err } @@ -281,7 +219,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // DescribeURN handles WeChat contact details func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLog) (map[string]string, error) { - accessToken, err := h.getAccessToken(channel) + accessToken, err := h.getAccessToken(ctx, channel, clog) if err != nil { return nil, err } @@ -311,9 +249,16 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn return map[string]string{"name": nickname}, nil } +func (h *handler) RedactValues(ch courier.Channel) []string { + return []string{ + ch.StringConfigForKey(courier.ConfigSecret, ""), + ch.StringConfigForKey(configAppSecret, ""), + } +} + // BuildAttachmentRequest download media for message attachment func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, channel courier.Channel, attachmentURL string, clog *courier.ChannelLog) (*http.Request, error) { - accessToken, err := h.getAccessToken(channel) + accessToken, err := h.getAccessToken(ctx, channel, clog) if err != nil { return nil, err } @@ -336,3 +281,67 @@ func (*handler) AttachmentRequestClient(ch courier.Channel) *http.Client { } var _ courier.AttachmentRequestBuilder = (*handler)(nil) + +func (h *handler) getAccessToken(ctx context.Context, channel courier.Channel, clog *courier.ChannelLog) (string, error) { + rc := h.Backend().RedisPool().Get() + defer rc.Close() + + tokenKey := fmt.Sprintf("channel-token:%s", channel.UUID().String()) + + h.fetchTokenMutex.Lock() + defer h.fetchTokenMutex.Unlock() + + token, err := redis.String(rc.Do("GET", tokenKey)) + if err != nil && err != redis.ErrNil { + return "", errors.Wrap(err, "error reading cached access token") + } + + if token != "" { + return token, nil + } + + token, expires, err := h.fetchAccessToken(ctx, channel, clog) + if err != nil { + return "", errors.Wrap(err, "error fetching new access token") + } + + _, err = rc.Do("SET", tokenKey, token, "EX", int(expires/time.Second)) + if err != nil { + return "", errors.Wrap(err, "error updating cached access token") + } + + return token, nil +} + +// fetchAccessToken tries to fetch a new token for our channel, setting the result in redis +func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel, clog *courier.ChannelLog) (string, time.Duration, error) { + form := url.Values{ + "grant_type": []string{"client_credential"}, + "appid": []string{channel.StringConfigForKey(configAppID, "")}, + "secret": []string{channel.StringConfigForKey(configAppSecret, "")}, + } + tokenURL, _ := url.Parse(fmt.Sprintf("%s/%s", sendURL, "token")) + tokenURL.RawQuery = form.Encode() + + req, _ := http.NewRequest(http.MethodGet, tokenURL.String(), nil) + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + req.Header.Set("Accept", "application/json") + + resp, respBody, err := handlers.RequestHTTP(req, clog) + if err != nil || resp.StatusCode/100 != 2 { + return "", 0, err + } + + token, err := jsonparser.GetString(respBody, "access_token") + if err != nil { + clog.Error(courier.ErrorResponseValueMissing("access_token")) + return "", 0, err + } + + expiration, err := jsonparser.GetInt(respBody, "expires_in") + if err != nil || expiration == 0 { + expiration = 7200 + } + + return token, time.Second * time.Duration(expiration), nil +} diff --git a/handlers/wechat/wechat_test.go b/handlers/wechat/wechat_test.go index e0d6eca95..b32045845 100644 --- a/handlers/wechat/wechat_test.go +++ b/handlers/wechat/wechat_test.go @@ -4,9 +4,7 @@ import ( "context" "crypto/sha1" "encoding/hex" - "fmt" "io" - "log" "net/http" "net/http/httptest" "net/url" @@ -18,6 +16,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/urns" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" @@ -25,7 +24,7 @@ import ( var testChannels = []courier.Channel{ test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WC", "2020", "US", - map[string]interface{}{courier.ConfigSecret: "secret", configAppSecret: "app-secret", configAppID: "app-id"}), + map[string]interface{}{courier.ConfigSecret: "secret123", configAppSecret: "app-secret123", configAppID: "app-id"}), } var ( @@ -97,7 +96,7 @@ func addValidSignature(r *http.Request) { timestamp := t.Format("20060102150405") nonce := "nonce" - stringSlice := []string{"secret", timestamp, nonce} + stringSlice := []string{"secret123", timestamp, nonce} sort.Strings(stringSlice) value := strings.Join(stringSlice, "") @@ -121,7 +120,7 @@ func addInvalidSignature(r *http.Request) { timestamp := t.Format("20060102150405") nonce := "nonce" - stringSlice := []string{"secret", timestamp, nonce} + stringSlice := []string{"secret123", timestamp, nonce} sort.Strings(stringSlice) value := strings.Join(stringSlice, "") @@ -172,56 +171,6 @@ func BenchmarkHandler(b *testing.B) { RunChannelBenchmarks(b, testChannels, newHandler(), testCases) } -func TestFetchAccessToken(t *testing.T) { - fetchCalled := false - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if strings.HasSuffix(r.URL.Path, "token") { - defer r.Body.Close() - // valid token - w.Write([]byte(`{"access_token": "TOKEN"}`)) - } - - // mark that we were called - fetchCalled = true - })) - sendURL = server.URL - fetchTimeout = time.Millisecond - - RunChannelTestCases(t, testChannels, newHandler(), []ChannelHandleTestCase{ - { - Label: "Receive Message", - URL: receiveURL, - Data: validMsg, - ExpectedRespStatus: 200, - ExpectedBodyContains: "", - ExpectedMsgText: Sp("Simple Message"), - ExpectedURN: "wechat:1234", - }, - { - Label: "Verify URL", - URL: receiveURL, - ExpectedRespStatus: 200, - ExpectedBodyContains: "SUCCESS", - PrepRequest: addValidSignature, - }, - { - Label: "Verify URL Invalid signature", - URL: receiveURL, - ExpectedRespStatus: 400, - ExpectedBodyContains: "unknown request", - PrepRequest: addInvalidSignature, - }, - }) - - // wait for our fetch to be called - time.Sleep(100 * time.Millisecond) - - if !fetchCalled { - t.Error("fetch access point should have been called") - } - -} - // mocks the call to the WeChat API func buildMockWCAPI(testCases []ChannelHandleTestCase) *httptest.Server { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -269,17 +218,14 @@ func TestDescribeURN(t *testing.T) { defer WCAPI.Close() mb := test.NewMockBackend() - conn := mb.RedisPool().Get() - - _, err := conn.Do("SET", "wechat_channel_access_token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ACCESS_TOKEN") - if err != nil { - log.Fatal(err) - } - conn.Close() + // ensure there's a cached access token + rc := mb.RedisPool().Get() + defer rc.Close() + rc.Do("SET", "channel-token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ACCESS_TOKEN") s := newServer(mb) - handler := &handler{NewBaseHandler(courier.ChannelType("WC"), "WeChat")} + handler := newHandler().(*handler) handler.Initialize(s) clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], handler.RedactValues(testChannels[0])) @@ -296,36 +242,46 @@ func TestDescribeURN(t *testing.T) { assert.Equal(t, metadata, tc.expectedMetadata) } - AssertChannelLogRedaction(t, clog, []string{"secret"}) + AssertChannelLogRedaction(t, clog, []string{"secret123"}) } -func TestBuildMediaRequest(t *testing.T) { +func TestBuildAttachmentRequest(t *testing.T) { mb := test.NewMockBackend() - conn := mb.RedisPool().Get() - _, err := conn.Do("SET", "wechat_channel_access_token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ACCESS_TOKEN") - if err != nil { - log.Fatal(err) - } + // reset send URL + sendURL = "https://api.weixin.qq.com/cgi-bin" + + defer httpx.SetRequestor(httpx.DefaultRequestor) + httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ + "https://api.weixin.qq.com/cgi-bin/token?appid=app-id&grant_type=client_credential&secret=app-secret123": { + httpx.NewMockResponse(http.StatusOK, nil, []byte(`{"access_token": "SESAME"}`)), + }, + })) + + // ensure that we start with no cached token + rc := mb.RedisPool().Get() + defer rc.Close() + rc.Do("DEL", "channel-token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab") - conn.Close() s := newServer(mb) - handler := &handler{NewBaseHandler(courier.ChannelType("WC"), "WeChat")} + handler := newHandler().(*handler) handler.Initialize(s) + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], handler.RedactValues(testChannels[0])) - tcs := []struct { - url string - }{ - { - fmt.Sprintf("%s/media/get?media_id=12", sendURL), - }, - } + // check that request has the fetched access token + req, err := handler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], "https://api.weixin.qq.com/cgi-bin/media/download.action?media_id=12", clog) + assert.NoError(t, err) + assert.Equal(t, "https://api.weixin.qq.com/cgi-bin/media/download.action?access_token=SESAME&media_id=12", req.URL.String()) - for _, tc := range tcs { - req, _ := handler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], tc.url, nil) - assert.Equal(t, fmt.Sprintf("%s/media/get?access_token=ACCESS_TOKEN&media_id=12", sendURL), req.URL.String()) - } + // and that we have a log for that request + assert.Len(t, clog.HTTPLogs(), 1) + assert.Equal(t, "https://api.weixin.qq.com/cgi-bin/token?appid=app-id&grant_type=client_credential&secret=**********", clog.HTTPLogs()[0].URL) + // check that another request reads token from cache + req, err = handler.BuildAttachmentRequest(context.Background(), mb, testChannels[0], "https://api.weixin.qq.com/cgi-bin/media/download.action?media_id=13", clog) + assert.NoError(t, err) + assert.Equal(t, "https://api.weixin.qq.com/cgi-bin/media/download.action?access_token=SESAME&media_id=13", req.URL.String()) + assert.Len(t, clog.HTTPLogs(), 1) } // setSendURL takes care of setting the sendURL to call @@ -388,18 +344,14 @@ var defaultSendTestCases = []ChannelSendTestCase{ } func setupBackend(mb *test.MockBackend) { - conn := mb.RedisPool().Get() - - _, err := conn.Do("SET", "wechat_channel_access_token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ACCESS_TOKEN") - if err != nil { - log.Fatal(err) - } - - conn.Close() + // ensure there's a cached access token + rc := mb.RedisPool().Get() + defer rc.Close() + rc.Do("SET", "channel-token:8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "ACCESS_TOKEN") } func TestSending(t *testing.T) { maxMsgLength = 160 - var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WC", "2020", "US", map[string]interface{}{configAppSecret: "secret", configAppID: "app-id"}) - RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"secret"}, setupBackend) + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "WC", "2020", "US", map[string]interface{}{configAppSecret: "secret123", configAppID: "app-id"}) + RunChannelSendTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"secret123"}, setupBackend) } From a2f09dec6a11d68249e3a55f16a87fc2cf578a4d Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 26 Oct 2022 13:47:53 -0500 Subject: [PATCH 254/294] Update CHANGELOG.md for v7.5.54 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 269ea6af4..7892c1a86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.54 +---------- + * Fetch access tokens for WeChat, JioChat channels as needed + v7.5.53 ---------- * Use redisx.IntervalHash for message de-duping checks From e33ea0490d6c21ea64ce49c14613237c2e96f999 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 27 Oct 2022 14:01:52 -0500 Subject: [PATCH 255/294] Update deps including phonenumbers --- go.mod | 20 ++++++++++---------- go.sum | 47 ++++++++++++++++++++++++----------------------- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index 726b785f9..bf7d6dac9 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/antchfx/xmlquery v1.3.12 - github.com/aws/aws-sdk-go v1.44.111 + github.com/aws/aws-sdk-go v1.44.124 github.com/buger/jsonparser v1.1.1 github.com/dghubble/oauth1 v0.7.1 github.com/evalphobia/logrus_sentry v0.8.2 @@ -13,16 +13,16 @@ require ( github.com/gomodule/redigo v1.8.9 github.com/gorilla/schema v1.2.0 github.com/jmoiron/sqlx v1.3.5 - github.com/lib/pq v1.10.6 + github.com/lib/pq v1.10.7 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.32.0 + github.com/nyaruka/gocommon v1.32.1 github.com/nyaruka/null v1.2.0 github.com/nyaruka/redisx v0.2.2 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.0 - github.com/stretchr/testify v1.8.0 - golang.org/x/mod v0.5.1 + github.com/stretchr/testify v1.8.1 + golang.org/x/mod v0.6.0 gopkg.in/go-playground/validator.v9 v9.31.0 gopkg.in/h2non/filetype.v1 v1.0.5 ) @@ -39,18 +39,18 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/kr/pretty v0.3.0 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/naoina/go-stringutil v0.1.0 // indirect github.com/naoina/toml v0.1.1 // indirect github.com/nyaruka/librato v1.0.0 // indirect - github.com/nyaruka/phonenumbers v1.1.1 // indirect + github.com/nyaruka/phonenumbers v1.1.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect - golang.org/x/net v0.0.0-20221004154528-8021a29435af // indirect - golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/net v0.1.0 // indirect + golang.org/x/sys v0.1.0 // indirect + golang.org/x/text v0.4.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index bac74b328..aa10d0717 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/antchfx/xmlquery v1.3.12 h1:6TMGpdjpO/P8VhjnaYPXuqT3qyJ/VsqoyNTmJzNBT github.com/antchfx/xmlquery v1.3.12/go.mod h1:3w2RvQvTz+DaT5fSgsELkSJcdNgkmg6vuXDEuhdwsPQ= github.com/antchfx/xpath v1.2.1 h1:qhp4EW6aCOVr5XIkT+l6LJ9ck/JsUH/yyauNgTQkBF8= github.com/antchfx/xpath v1.2.1/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= -github.com/aws/aws-sdk-go v1.44.111 h1:AcWfOgeedSQ4gQVwcIe6aLxpQNJMloZQyqnr7Dzki+s= -github.com/aws/aws-sdk-go v1.44.111/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.124 h1:Xe1WQRUUekZf6ZFm3SD0vplB/AP/hymVqMiRS9LQRIs= +github.com/aws/aws-sdk-go v1.44.124/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s= @@ -53,10 +53,9 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfC github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -67,8 +66,8 @@ github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= -github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= +github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks= @@ -77,24 +76,25 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.32.0 h1:No9EGpym15WvWmbdNcKytvgQTpnEjTEyEf+doaaysSY= -github.com/nyaruka/gocommon v1.32.0/go.mod h1:PApT/06fP5Tzs4/kbkJ+rVoyOc9Lbqm1lR0ow8Vqzp0= +github.com/nyaruka/gocommon v1.32.1 h1:bei12SNM084Svcaaxj9ZexFEExnhe2trxd3FkmNS2n0= +github.com/nyaruka/gocommon v1.32.1/go.mod h1:k03R7UY1IX65qPEncv7MgvQx7BZ2laR+ikN1GQjTMbY= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= github.com/nyaruka/null v1.2.0/go.mod h1:HSAFbLNOaEhHnoU0VCveCPz0GDtJ3GEtFWhvnBNkhPE= -github.com/nyaruka/phonenumbers v1.1.1 h1:fyoZmpLN2VCmAnc51XcrNOUVP2wT1ZzQl348ggIaXII= -github.com/nyaruka/phonenumbers v1.1.1/go.mod h1:cGaEsOrLjIL0iKGqJR5Rfywy86dSkbApEpXuM9KySNA= +github.com/nyaruka/phonenumbers v1.1.2 h1:MIDljnA08HCUzgNOrkCYja7CJ5U9ylZ+U3Sge8RWW14= +github.com/nyaruka/phonenumbers v1.1.2/go.mod h1:cGaEsOrLjIL0iKGqJR5Rfywy86dSkbApEpXuM9KySNA= github.com/nyaruka/redisx v0.2.2 h1:OAJ4g1So2opn6O5akDWEWiDWgEOvPMKU10EUCG/Nv9Y= github.com/nyaruka/redisx v0.2.2/go.mod h1:cdbAm4y/+oFWu7qFzH2ERPeqRXJC2CtgRhwcBacM4Oc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -103,31 +103,34 @@ github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4= -golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI= -golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -136,10 +139,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M= gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= From c59334715e0cd797138ca0ad092391fc3ccdb76c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 27 Oct 2022 14:07:06 -0500 Subject: [PATCH 256/294] Update CHANGELOG.md for v7.5.55 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7892c1a86..ac1fcd091 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.55 +---------- + * Update deps including phonenumbers + v7.5.54 ---------- * Fetch access tokens for WeChat, JioChat channels as needed From 9ecb8c7c737987d9e527122b3dc1d4d44a731713 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 31 Oct 2022 11:19:42 -0500 Subject: [PATCH 257/294] Allow empty attachments, e.g. a txt file --- attachments.go | 3 --- attachments_test.go | 8 -------- 2 files changed, 11 deletions(-) diff --git a/attachments.go b/attachments.go index 53d74c585..5bb3c1908 100644 --- a/attachments.go +++ b/attachments.go @@ -99,9 +99,6 @@ func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, at // just have problems return nil, errors.Errorf("non 2XX response code (%d) trying to fetch attachment", trace.Response.StatusCode) } - if len(trace.ResponseBody) == 0 { - return nil, errors.New("received empty response trying to fetch attachment") - } mimeType := "" extension := filepath.Ext(parsedURL.Path) diff --git a/attachments_test.go b/attachments_test.go index d89a25226..4877c274a 100644 --- a/attachments_test.go +++ b/attachments_test.go @@ -22,9 +22,6 @@ func TestFetchAndStoreAttachment(t *testing.T) { "http://mock.com/media/hello.mp3": { httpx.NewMockResponse(502, nil, []byte(`Timeout`)), }, - "http://mock.com/media/hello.avi": { - httpx.NewMockResponse(200, nil, nil), // 200 status code but empty response - }, })) defer uuids.SetGenerator(uuids.DefaultGenerator) @@ -53,9 +50,4 @@ func TestFetchAndStoreAttachment(t *testing.T) { assert.EqualError(t, err, "non 2XX response code (502) trying to fetch attachment") assert.Nil(t, att) assert.Len(t, mb.SavedAttachments(), 1) - - att, err = courier.FetchAndStoreAttachment(ctx, mb, mockChannel, "http://mock.com/media/hello.avi", clog) - assert.EqualError(t, err, "received empty response trying to fetch attachment") - assert.Nil(t, att) - assert.Len(t, mb.SavedAttachments(), 1) } From d4687455b3c482b2333e8f62c626f8a7a041128a Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 31 Oct 2022 12:04:42 -0500 Subject: [PATCH 258/294] Update CHANGELOG.md for v7.5.56 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac1fcd091..11defccdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.56 +---------- + * Allow empty attachments, e.g. a txt file + v7.5.55 ---------- * Update deps including phonenumbers From 7dc139cc0340a176dc794beb390291e56070d1d6 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 31 Oct 2022 12:51:23 -0500 Subject: [PATCH 259/294] Update to latest gocommon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index bf7d6dac9..3fed43a26 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.7 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.32.1 + github.com/nyaruka/gocommon v1.32.2 github.com/nyaruka/null v1.2.0 github.com/nyaruka/redisx v0.2.2 github.com/patrickmn/go-cache v2.1.0+incompatible diff --git a/go.sum b/go.sum index aa10d0717..a1234e8f2 100644 --- a/go.sum +++ b/go.sum @@ -76,8 +76,8 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.32.1 h1:bei12SNM084Svcaaxj9ZexFEExnhe2trxd3FkmNS2n0= -github.com/nyaruka/gocommon v1.32.1/go.mod h1:k03R7UY1IX65qPEncv7MgvQx7BZ2laR+ikN1GQjTMbY= +github.com/nyaruka/gocommon v1.32.2 h1:SsrVBnccJ9ZcRApAYlyO/lyFG3rREb6d0x2K9Pgtk3s= +github.com/nyaruka/gocommon v1.32.2/go.mod h1:k03R7UY1IX65qPEncv7MgvQx7BZ2laR+ikN1GQjTMbY= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= From 509e56d1f785d759ff044333c6d5892c51b1d565 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 31 Oct 2022 12:53:19 -0500 Subject: [PATCH 260/294] Update CHANGELOG.md for v7.5.57 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11defccdc..548d91ff9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.57 +---------- + * Update to latest gocommon + v7.5.56 ---------- * Allow empty attachments, e.g. a txt file From a27c6160ad012bf32009781e31492d96ff3693c9 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 7 Nov 2022 14:46:15 -0500 Subject: [PATCH 261/294] Set server idle timeout to 90 seconds --- server.go | 1 + 1 file changed, 1 insertion(+) diff --git a/server.go b/server.go index aa3d3aed4..f376046fa 100644 --- a/server.go +++ b/server.go @@ -127,6 +127,7 @@ func (s *server) Start() error { Handler: s.router, ReadTimeout: 30 * time.Second, WriteTimeout: 30 * time.Second, + IdleTimeout: 90 * time.Second, } s.waitGroup.Add(1) From b744d8fdafaa11c05b0953ee3da711391a5acd0c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 7 Nov 2022 15:30:18 -0500 Subject: [PATCH 262/294] Update CHANGELOG.md for v7.5.58 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 548d91ff9..1af9ff2e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.58 +---------- + * Set server idle timeout to 90 seconds + * Test against redis 6.2 and postgres 14 + v7.5.57 ---------- * Update to latest gocommon From fc15199bc2ceb062bfd53177089b3a3b14cda2c1 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 9 Nov 2022 11:21:14 -0500 Subject: [PATCH 263/294] Fix returning non-nil courier.Channel for deleted channels --- backends/rapidpro/backend.go | 12 ++++++++++-- backends/rapidpro/backend_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 33a3b0f0d..5b1ebc811 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -54,7 +54,11 @@ func (b *backend) GetChannel(ctx context.Context, ct courier.ChannelType, uuid c timeout, cancel := context.WithTimeout(ctx, backendTimeout) defer cancel() - return getChannel(timeout, b.db, ct, uuid) + ch, err := getChannel(timeout, b.db, ct, uuid) + if err != nil { + return nil, err // so we don't return a non-nil interface and nil ptr + } + return ch, err } // GetChannelByAddress returns the channel with the passed in type and address @@ -62,7 +66,11 @@ func (b *backend) GetChannelByAddress(ctx context.Context, ct courier.ChannelTyp timeout, cancel := context.WithTimeout(ctx, backendTimeout) defer cancel() - return getChannelByAddress(timeout, b.db, ct, address) + ch, err := getChannelByAddress(timeout, b.db, ct, address) + if err != nil { + return nil, err // so we don't return a non-nil interface and nil ptr + } + return ch, err } // GetContact returns the contact for the passed in channel and URN diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index 1aaef4e68..aa3674143 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -978,7 +978,33 @@ func (ts *BackendTestSuite) TestChannel() { ts.False(exChannel2.HasRole(courier.ChannelRoleReceive)) ts.False(exChannel2.HasRole(courier.ChannelRoleCall)) ts.False(exChannel2.HasRole(courier.ChannelRoleAnswer)) +} + +func (ts *BackendTestSuite) TestGetChannel() { + ctx := context.Background() + + knUUID, _ := courier.NewChannelUUID("dbc126ed-66bc-4e28-b67b-81dc3327c95d") + xxUUID, _ := courier.NewChannelUUID("0a1256fe-c6e4-494d-99d3-576286f31d3b") // doesn't exist + + ch, err := ts.b.GetChannel(ctx, courier.ChannelType("KN"), knUUID) + ts.Assert().NoError(err) + ts.Assert().NotNil(ch) + ts.Assert().Equal(knUUID, ch.UUID()) + + ch, err = ts.b.GetChannel(ctx, courier.ChannelType("KN"), knUUID) // from cache + ts.Assert().NoError(err) + ts.Assert().NotNil(ch) + ts.Assert().Equal(knUUID, ch.UUID()) + + ch, err = ts.b.GetChannel(ctx, courier.ChannelType("KN"), xxUUID) + ts.Assert().Error(err) + ts.Assert().Nil(ch) + ts.Assert().True(ch == nil) // https://github.com/stretchr/testify/issues/503 + ch, err = ts.b.GetChannel(ctx, courier.ChannelType("KN"), xxUUID) // from cache + ts.Assert().Error(err) + ts.Assert().Nil(ch) + ts.Assert().True(ch == nil) // https://github.com/stretchr/testify/issues/503 } func (ts *BackendTestSuite) TestWriteChanneLog() { From 9f98d6a50e9d9919954e337e1659059dde7958b8 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 9 Nov 2022 11:29:52 -0500 Subject: [PATCH 264/294] Update CHANGELOG.md for v7.5.59 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1af9ff2e8..dca636fc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.59 +---------- + * Fix returning non-nil courier.Channel for deleted channels + v7.5.58 ---------- * Set server idle timeout to 90 seconds From 06ef0c9b1e6338f605c61c6c77b47fcdffac27de Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 11 Nov 2022 10:49:05 -0500 Subject: [PATCH 265/294] Update attachment fetching to handle non-200 response as an available attachment --- attachments.go | 23 ++++++++++++++--------- attachments_test.go | 10 ++++++++-- server.go | 4 ++-- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/attachments.go b/attachments.go index 5bb3c1908..b8014779f 100644 --- a/attachments.go +++ b/attachments.go @@ -32,36 +32,43 @@ type fetchAttachmentRequest struct { URL string `json:"url" validate:"required"` } -func fetchAttachment(ctx context.Context, b Backend, r *http.Request) (*Attachment, *ChannelLog, error) { +type fetchAttachmentResponse struct { + Attachment *Attachment `json:"attachment"` + LogUUID ChannelLogUUID `json:"log_uuid"` +} + +func fetchAttachment(ctx context.Context, b Backend, r *http.Request) (*fetchAttachmentResponse, error) { body, err := io.ReadAll(r.Body) if err != nil { - return nil, nil, errors.Wrap(err, "error reading request body") + return nil, errors.Wrap(err, "error reading request body") } fa := &fetchAttachmentRequest{} if err := json.Unmarshal(body, fa); err != nil { - return nil, nil, errors.Wrap(err, "error unmarshalling request") + return nil, errors.Wrap(err, "error unmarshalling request") } if err := utils.Validate(fa); err != nil { - return nil, nil, err + return nil, err } ch, err := b.GetChannel(ctx, fa.ChannelType, fa.ChannelUUID) if err != nil { - return nil, nil, errors.Wrap(err, "error getting channel") + return nil, errors.Wrap(err, "error getting channel") } clog := NewChannelLogForAttachmentFetch(ch, GetHandler(ch.ChannelType()).RedactValues(ch)) attachment, err := FetchAndStoreAttachment(ctx, b, ch, fa.URL, clog) + resp := &fetchAttachmentResponse{Attachment: attachment, LogUUID: clog.UUID()} + clog.End() if err := b.WriteChannelLog(ctx, clog); err != nil { logrus.WithError(err).Error() } - return attachment, clog, err + return resp, err } func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, attURL string, clog *ChannelLog) (*Attachment, error) { @@ -95,9 +102,7 @@ func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, at return nil, err } if trace.Response.StatusCode/100 != 2 { - // TODO once we're confident this is working maybe we don't log errors like this since sometimes channels - // just have problems - return nil, errors.Errorf("non 2XX response code (%d) trying to fetch attachment", trace.Response.StatusCode) + return &Attachment{ContentType: "unavailable", URL: attURL, Size: 0}, nil } mimeType := "" diff --git a/attachments_test.go b/attachments_test.go index 4877c274a..aa1ab8eb9 100644 --- a/attachments_test.go +++ b/attachments_test.go @@ -47,7 +47,13 @@ func TestFetchAndStoreAttachment(t *testing.T) { assert.Equal(t, "http://mock.com/media/hello.jpg", clog.HTTPLogs()[0].URL) att, err = courier.FetchAndStoreAttachment(ctx, mb, mockChannel, "http://mock.com/media/hello.mp3", clog) - assert.EqualError(t, err, "non 2XX response code (502) trying to fetch attachment") - assert.Nil(t, att) + assert.NoError(t, err) + assert.Equal(t, "unavailable", att.ContentType) + assert.Equal(t, "http://mock.com/media/hello.mp3", att.URL) // the original URL + assert.Equal(t, 0, att.Size) + + // should have a logged HTTP request but no attachments will have been saved to storage + assert.Len(t, clog.HTTPLogs(), 2) + assert.Equal(t, "http://mock.com/media/hello.mp3", clog.HTTPLogs()[1].URL) assert.Len(t, mb.SavedAttachments(), 1) } diff --git a/server.go b/server.go index f376046fa..9aa08d553 100644 --- a/server.go +++ b/server.go @@ -400,7 +400,7 @@ func (s *server) handleFetchAttachment(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(context.Background(), time.Minute*1) defer cancel() - attachment, clog, err := fetchAttachment(ctx, s.backend, r) + resp, err := fetchAttachment(ctx, s.backend, r) if err != nil { logrus.WithError(err).Error() WriteError(w, http.StatusBadRequest, err) @@ -409,7 +409,7 @@ func (s *server) handleFetchAttachment(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - w.Write(jsonx.MustMarshal(map[string]any{"attachment": attachment, "log_uuid": clog.UUID()})) + w.Write(jsonx.MustMarshal(resp)) } func (s *server) handle404(w http.ResponseWriter, r *http.Request) { From 631f3deedc43a9ef7ab01f752920b730c342181a Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 11 Nov 2022 15:45:17 -0500 Subject: [PATCH 266/294] Allow msg id to be passed to fetch attachment requests and saved on the channel log --- attachments.go | 3 ++- attachments_test.go | 2 +- channel_log.go | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/attachments.go b/attachments.go index b8014779f..720bb023f 100644 --- a/attachments.go +++ b/attachments.go @@ -30,6 +30,7 @@ type fetchAttachmentRequest struct { ChannelType ChannelType `json:"channel_type" validate:"required"` ChannelUUID ChannelUUID `json:"channel_uuid" validate:"required,uuid"` URL string `json:"url" validate:"required"` + MsgID MsgID `json:"msg_id"` } type fetchAttachmentResponse struct { @@ -56,7 +57,7 @@ func fetchAttachment(ctx context.Context, b Backend, r *http.Request) (*fetchAtt return nil, errors.Wrap(err, "error getting channel") } - clog := NewChannelLogForAttachmentFetch(ch, GetHandler(ch.ChannelType()).RedactValues(ch)) + clog := NewChannelLogForAttachmentFetch(ch, fa.MsgID, GetHandler(ch.ChannelType()).RedactValues(ch)) attachment, err := FetchAndStoreAttachment(ctx, b, ch, fa.URL, clog) diff --git a/attachments_test.go b/attachments_test.go index aa1ab8eb9..0208f3661 100644 --- a/attachments_test.go +++ b/attachments_test.go @@ -33,7 +33,7 @@ func TestFetchAndStoreAttachment(t *testing.T) { mockChannel := test.NewMockChannel("e4bb1578-29da-4fa5-a214-9da19dd24230", "MCK", "2020", "US", map[string]interface{}{}) mb.AddChannel(mockChannel) - clog := courier.NewChannelLogForAttachmentFetch(mockChannel, []string{"sesame"}) + clog := courier.NewChannelLogForAttachmentFetch(mockChannel, courier.MsgID(123), []string{"sesame"}) att, err := courier.FetchAndStoreAttachment(ctx, mb, mockChannel, "http://mock.com/media/hello.jpg", clog) assert.NoError(t, err) diff --git a/channel_log.go b/channel_log.go index 6399ccabd..5bdf96a86 100644 --- a/channel_log.go +++ b/channel_log.go @@ -107,8 +107,8 @@ func NewChannelLogForSend(msg Msg, redactVals []string) *ChannelLog { } // NewChannelLogForSend creates a new channel log for an attachment fetch -func NewChannelLogForAttachmentFetch(ch Channel, redactVals []string) *ChannelLog { - return newChannelLog(ChannelLogTypeAttachmentFetch, ch, nil, NilMsgID, redactVals) +func NewChannelLogForAttachmentFetch(ch Channel, msgID MsgID, redactVals []string) *ChannelLog { + return newChannelLog(ChannelLogTypeAttachmentFetch, ch, nil, msgID, redactVals) } // NewChannelLog creates a new channel log with the given type and channel From 3793ff07a19793a7e71720d8f5c201984dded5c0 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 11 Nov 2022 16:01:56 -0500 Subject: [PATCH 267/294] Update CHANGELOG.md for v7.5.60 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dca636fc4..e1e5220df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.60 +---------- + * Allow msg id to be passed to fetch attachment requests and saved on the channel log + * Update attachment fetching to handle non-200 response as an unavailable attachment + v7.5.59 ---------- * Fix returning non-nil courier.Channel for deleted channels From 4798a39e397a9830b0706c3ffdf366dbceafd7af Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 17 Nov 2022 12:35:58 -0500 Subject: [PATCH 268/294] Don't add returned err to channel log if it has logged errors already and improve error logging for some more channel types --- backends/rapidpro/backend_test.go | 5 ++--- channel_log.go | 5 +++++ channel_log_test.go | 16 ++++++++++------ handlers/external/external.go | 6 +++--- handlers/external/external_test.go | 2 +- handlers/i2sms/i2sms.go | 2 +- handlers/i2sms/i2sms_test.go | 2 +- handlers/messangi/messangi.go | 4 ++-- handlers/messangi/messangi_test.go | 2 +- handlers/nexmo/nexmo.go | 12 +++++++++--- handlers/nexmo/nexmo_test.go | 4 ++-- handlers/test.go | 6 +++--- handlers/twiml/twiml.go | 2 +- handlers/twiml/twiml_test.go | 8 ++++---- sender.go | 6 +++++- test/handler.go | 2 +- 16 files changed, 51 insertions(+), 33 deletions(-) diff --git a/backends/rapidpro/backend_test.go b/backends/rapidpro/backend_test.go index aa3674143..3390ad40f 100644 --- a/backends/rapidpro/backend_test.go +++ b/backends/rapidpro/backend_test.go @@ -4,7 +4,6 @@ import ( "context" "encoding/base64" "encoding/json" - "errors" "fmt" "io" "log" @@ -1029,7 +1028,7 @@ func (ts *BackendTestSuite) TestWriteChanneLog() { clog := courier.NewChannelLog(courier.ChannelLogTypeTokenRefresh, channel, nil) clog.HTTP(trace) - clog.RawError(errors.New("this is an error")) + clog.Error(courier.ErrorResponseStatusCode()) err = ts.b.WriteChannelLog(ctx, clog) ts.NoError(err) @@ -1038,7 +1037,7 @@ func (ts *BackendTestSuite) TestWriteChanneLog() { assertdb.Query(ts.T(), ts.b.db, `SELECT count(*) FROM channels_channellog`).Returns(1) assertdb.Query(ts.T(), ts.b.db, `SELECT channel_id, http_logs->0->>'url' AS url, errors->0->>'message' AS err FROM channels_channellog`). - Columns(map[string]interface{}{"channel_id": int64(channel.ID()), "url": "https://api.messages.com/send.json", "err": "this is an error"}) + Columns(map[string]interface{}{"channel_id": int64(channel.ID()), "url": "https://api.messages.com/send.json", "err": "Unexpected response status code."}) } func (ts *BackendTestSuite) TestSaveAttachment() { diff --git a/channel_log.go b/channel_log.go index 5bdf96a86..fb7b27e18 100644 --- a/channel_log.go +++ b/channel_log.go @@ -45,6 +45,10 @@ func ErrorResponseUnparseable(format string) *ChannelError { return NewChannelError(fmt.Sprintf("Unable to parse response as %s.", format), "core:response_unparseable") } +func ErrorResponseUnexpected(expected string) *ChannelError { + return NewChannelError(fmt.Sprintf("Expected response to be '%s'.", expected), "core:response_unexpected") +} + func ErrorResponseValueMissing(key string) *ChannelError { return NewChannelError(fmt.Sprintf("Unable to find '%s' response.", key), "core:response_value_missing") } @@ -138,6 +142,7 @@ func (l *ChannelLog) Error(e *ChannelError) { l.errors = append(l.errors, e.Redact(l.redactor)) } +// Deprecated: channel handlers should add user-facing error messages via .Error() instead func (l *ChannelLog) RawError(err error) { l.Error(NewChannelError(err.Error(), "")) } diff --git a/channel_log_test.go b/channel_log_test.go index 3746c9837..77a876ae3 100644 --- a/channel_log_test.go +++ b/channel_log_test.go @@ -1,7 +1,6 @@ package courier_test import ( - "errors" "net/http" "testing" "time" @@ -41,8 +40,8 @@ func TestChannelLog(t *testing.T) { assert.EqualError(t, err, "unable to connect to server") clog.HTTP(trace) - clog.Error(courier.NewChannelError("Something not right", "twilio:23456")) - clog.RawError(errors.New("this is an error")) + clog.Error(courier.NewChannelError("Something not right.", "twilio:23456")) + clog.Error(courier.ErrorResponseStatusCode()) clog.End() assert.Equal(t, courier.ChannelLogUUID("c00e5d67-c275-4389-aded-7d8b151cbd5b"), clog.UUID()) @@ -66,12 +65,12 @@ func TestChannelLog(t *testing.T) { assert.Equal(t, "", hlog2.Response) err1 := clog.Errors()[0] - assert.Equal(t, "Something not right", err1.Message()) + assert.Equal(t, "Something not right.", err1.Message()) assert.Equal(t, "twilio:23456", err1.Code()) err2 := clog.Errors()[1] - assert.Equal(t, "this is an error", err2.Message()) - assert.Equal(t, "", err2.Code()) + assert.Equal(t, "Unexpected response status code.", err2.Message()) + assert.Equal(t, "core:response_status_code", err2.Code()) clog.SetMsgID(courier.NewMsgID(123)) clog.SetType(courier.ChannelLogTypeEventReceive) @@ -96,6 +95,11 @@ func TestChannelErrors(t *testing.T) { "Unable to parse response as FOO.", "core:response_unparseable", }, + { + courier.ErrorResponseUnexpected("all good!"), + "Expected response to be 'all good!'.", + "core:response_unexpected", + }, { courier.ErrorResponseValueMissing("id"), "Unable to find 'id' response.", diff --git a/handlers/external/external.go b/handlers/external/external.go index fae13ca0d..2bd1e8383 100644 --- a/handlers/external/external.go +++ b/handlers/external/external.go @@ -279,7 +279,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann // figure out what encoding to tell kannel to send as encoding := msg.Channel().StringConfigForKey(configEncoding, encodingDefault) - responseContent := msg.Channel().StringConfigForKey(configMTResponseCheck, "") + responseCheck := msg.Channel().StringConfigForKey(configMTResponseCheck, "") sendMethod := msg.Channel().StringConfigForKey(courier.ConfigSendMethod, http.MethodPost) sendBody := msg.Channel().StringConfigForKey(courier.ConfigSendBody, "") contentType := msg.Channel().StringConfigForKey(courier.ConfigContentType, contentURLEncoded) @@ -366,10 +366,10 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } - if responseContent == "" || strings.Contains(string(respBody), responseContent) { + if responseCheck == "" || strings.Contains(string(respBody), responseCheck) { status.SetStatus(courier.MsgWired) } else { - clog.RawError(fmt.Errorf("Received invalid response content: %s", string(respBody))) + clog.Error(courier.ErrorResponseUnexpected(responseCheck)) } } diff --git a/handlers/external/external_test.go b/handlers/external/external_test.go index 3a27e875f..12146607c 100644 --- a/handlers/external/external_test.go +++ b/handlers/external/external_test.go @@ -625,7 +625,7 @@ var xmlSendWithResponseContentTestCases = []ChannelSendTestCase{ ExpectedRequestBody: `+250788383383Error Message2020`, ExpectedHeaders: map[string]string{"Content-Type": "text/xml; charset=utf-8"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Received invalid response content: 1", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseUnexpected("0")}, SendPrep: setSendURL, }, { diff --git a/handlers/i2sms/i2sms.go b/handlers/i2sms/i2sms.go index e96a6ab68..d0e266fec 100644 --- a/handlers/i2sms/i2sms.go +++ b/handlers/i2sms/i2sms.go @@ -136,7 +136,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann status.SetExternalID(response.Result.SessionID) } else { status.SetStatus(courier.MsgFailed) - clog.RawError(fmt.Errorf("Received invalid response code: %s", response.ErrorCode)) + clog.Error(courier.ErrorResponseValueUnexpected("error_code", "00")) break } } diff --git a/handlers/i2sms/i2sms_test.go b/handlers/i2sms/i2sms_test.go index ca5d6538a..ce8e9ae14 100644 --- a/handlers/i2sms/i2sms_test.go +++ b/handlers/i2sms/i2sms_test.go @@ -84,7 +84,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"result":{}, "error_code": "10", "error_desc": "Failed"}`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Received invalid response code: 10", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueUnexpected("error_code", "00")}, SendPrep: setSendURL, }, { diff --git a/handlers/messangi/messangi.go b/handlers/messangi/messangi.go index 85139b482..a1b92e758 100644 --- a/handlers/messangi/messangi.go +++ b/handlers/messangi/messangi.go @@ -105,7 +105,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann response := &mtResponse{} err = xml.Unmarshal(respBody, response) if err != nil { - clog.RawError(err) + clog.Error(courier.ErrorResponseUnparseable("XML")) break } @@ -114,7 +114,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann status.SetStatus(courier.MsgWired) } else { status.SetStatus(courier.MsgFailed) - clog.RawError(fmt.Errorf("Received invalid response description: %s", response.Description)) + clog.Error(courier.ErrorResponseValueUnexpected("status", "OK")) break } } diff --git a/handlers/messangi/messangi_test.go b/handlers/messangi/messangi_test.go index bd34eada8..36693567f 100644 --- a/handlers/messangi/messangi_test.go +++ b/handlers/messangi/messangi_test.go @@ -91,7 +91,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `sendMTERRORCompleted`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Received invalid response description: Completed", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueUnexpected("status", "OK")}, SendPrep: setSendURL, }, } diff --git a/handlers/nexmo/nexmo.go b/handlers/nexmo/nexmo.go index cb70f30b9..bb5830340 100644 --- a/handlers/nexmo/nexmo.go +++ b/handlers/nexmo/nexmo.go @@ -15,7 +15,6 @@ import ( "github.com/nyaruka/gocommon/gsm7" "github.com/buger/jsonparser" - "github.com/pkg/errors" ) const ( @@ -53,10 +52,12 @@ func (h *handler) Initialize(s courier.Server) error { return nil } +// https://developer.vonage.com/messaging/sms/guides/delivery-receipts type statusForm struct { To string `name:"to"` - MessageID string `name:"messageID"` + MessageID string `name:"messageId"` Status string `name:"status"` + ErrCode int `name:"err-code"` } var statusMappings = map[string]courier.MsgStatusValue{ @@ -83,6 +84,10 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "ignoring unknown status report") } + if form.ErrCode != 0 { + clog.Error(courier.ErrorServiceSpecific("vonage", strconv.Itoa(form.ErrCode), "")) + } + status := h.Backend().NewMsgStatusForExternalID(channel, form.MessageID, msgStatus, clog) return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) @@ -179,7 +184,8 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann nexmoStatus, err := jsonparser.GetString(respBody, "messages", "[0]", "status") if err != nil || nexmoStatus != "0" { - clog.RawError(errors.Errorf("failed to send message, received error status [%s]", nexmoStatus)) + // https://developer.vonage.com/messaging/sms/guides/troubleshooting-sms + clog.Error(courier.ErrorServiceSpecific("vonage", nexmoStatus, "")) return status, nil } diff --git a/handlers/nexmo/nexmo_test.go b/handlers/nexmo/nexmo_test.go index 8fe2fb00e..3bf170da6 100644 --- a/handlers/nexmo/nexmo_test.go +++ b/handlers/nexmo/nexmo_test.go @@ -169,7 +169,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Error status", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("failed to send message, received error status [10]", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("vonage", "10", "")}, SendPrep: setSendURL, }, { @@ -200,7 +200,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("failed to send message, received error status [1]", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("vonage", "1", "")}, SendPrep: setSendURL, }, } diff --git a/handlers/test.go b/handlers/test.go index 1ee2d56ff..6d83eb4ae 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -348,9 +348,9 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour status, err := handler.Send(ctx, msg, clog) cancel() - // we don't currently distinguish between a returned error and logged errors - if err != nil { - clog.RawError(err) + // sender adds returned error to channel log if there aren't other logged errors + if err != nil && len(clog.Errors()) == 0 { + clog.Error(courier.NewChannelError(err.Error(), "")) } assert.Equal(t, tc.ExpectedErrors, clog.Errors(), "unexpected errors logged") diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index 7b777f6c6..7f79cf40a 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -299,7 +299,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, err } } - clog.RawError(errors.Errorf("received error code from twilio '%d'", errorCode)) + clog.Error(courier.ErrorServiceSpecific("twilio", strconv.Itoa(int(errorCode)), "")) return status, nil } } diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index d5dfcc082..0ac6d8726 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -350,7 +350,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStopEvent: true, ExpectedMsgStatus: "F", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "")}, SendPrep: setSendURL, }, { @@ -457,7 +457,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedStopEvent: true, ExpectedMsgStatus: "F", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "")}, SendPrep: setSendURL, }, { @@ -542,7 +542,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "F", ExpectedStopEvent: true, - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "")}, SendPrep: setSendURL, }, { @@ -627,7 +627,7 @@ var swSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "F", ExpectedStopEvent: true, - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received error code from twilio '21610'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "")}, SendPrep: setSendURL, }, { diff --git a/sender.go b/sender.go index 5430b2c7b..649450b62 100644 --- a/sender.go +++ b/sender.go @@ -214,7 +214,11 @@ func (w *Sender) sendMessage(msg Msg) { if err != nil { log.WithError(err).WithField("elapsed", duration).Error("error sending message") - clog.RawError(err) + + // handlers should log errors implicitly with user friendly messages.. but if not.. add what we have + if len(clog.Errors()) == 0 { + clog.Error(NewChannelError(err.Error(), "")) + } // possible for handlers to only return an error in which case we construct an error status if status == nil { diff --git a/test/handler.go b/test/handler.go index b32ea2ea4..77090044f 100644 --- a/test/handler.go +++ b/test/handler.go @@ -51,7 +51,7 @@ func (h *mockHandler) Send(ctx context.Context, msg courier.Msg, clog *courier.C clog.HTTP(trace) // log an error than contains a value that should be redacted - clog.RawError(errors.New("contains sesame seeds")) + clog.Error(courier.NewChannelError("contains sesame seeds", "")) return h.backend.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgSent, clog), nil } From 55dfc075cff75064d9d5320fb42de9d01e13dcba Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 17 Nov 2022 14:26:23 -0500 Subject: [PATCH 269/294] Resolve error codes to messages for Twilio and Vonage --- channel_log_test.go | 11 ++++---- handlers/nexmo/nexmo.go | 54 ++++++++++++++++++++++++++++++++++-- handlers/nexmo/nexmo_test.go | 10 +++---- handlers/twiml/errors.json | 1 + handlers/twiml/twiml.go | 12 +++++++- handlers/twiml/twiml_test.go | 8 +++--- tools/twiml_errors.py | 9 ++++++ 7 files changed, 88 insertions(+), 17 deletions(-) create mode 100644 handlers/twiml/errors.json create mode 100755 tools/twiml_errors.py diff --git a/channel_log_test.go b/channel_log_test.go index 77a876ae3..17516bddc 100644 --- a/channel_log_test.go +++ b/channel_log_test.go @@ -1,6 +1,7 @@ package courier_test import ( + "errors" "net/http" "testing" "time" @@ -40,8 +41,8 @@ func TestChannelLog(t *testing.T) { assert.EqualError(t, err, "unable to connect to server") clog.HTTP(trace) - clog.Error(courier.NewChannelError("Something not right.", "twilio:23456")) - clog.Error(courier.ErrorResponseStatusCode()) + clog.Error(courier.NewChannelError("Something not right", "twilio:23456")) + clog.RawError(errors.New("this is an error")) clog.End() assert.Equal(t, courier.ChannelLogUUID("c00e5d67-c275-4389-aded-7d8b151cbd5b"), clog.UUID()) @@ -65,12 +66,12 @@ func TestChannelLog(t *testing.T) { assert.Equal(t, "", hlog2.Response) err1 := clog.Errors()[0] - assert.Equal(t, "Something not right.", err1.Message()) + assert.Equal(t, "Something not right", err1.Message()) assert.Equal(t, "twilio:23456", err1.Code()) err2 := clog.Errors()[1] - assert.Equal(t, "Unexpected response status code.", err2.Message()) - assert.Equal(t, "core:response_status_code", err2.Code()) + assert.Equal(t, "this is an error", err2.Message()) + assert.Equal(t, "", err2.Code()) clog.SetMsgID(courier.NewMsgID(123)) clog.SetType(courier.ChannelLogTypeEventReceive) diff --git a/handlers/nexmo/nexmo.go b/handlers/nexmo/nexmo.go index bb5830340..fed9bfe2a 100644 --- a/handlers/nexmo/nexmo.go +++ b/handlers/nexmo/nexmo.go @@ -28,6 +28,55 @@ var ( maxMsgLength = 1600 sendURL = "https://rest.nexmo.com/sms/json" throttledRE = regexp.MustCompile(`.*Throughput Rate Exceeded - please wait \[ (\d+) \] and retry.*`) + + // https://developer.vonage.com/messaging/sms/guides/troubleshooting-sms#sms-api-error-codes + sendErrorCodes = map[int]string{ + 1: "Throttled", + 2: "Missing Parameters", + 3: "Invalid Parameters", + 4: "Invalid Credentials", + 5: "Internal Error", + 6: "Invalid Message", + 7: "Number Barred", + 8: "Partner Account Barred", + 9: "Partner Quota Violation", + 10: "Too Many Existing Binds", + 11: "Account Not Enabled For HTTP", + 12: "Message Too Long", + 14: "Invalid Signature", + 15: "Invalid Sender Address", + 22: "Invalid Network Code", + 23: "Invalid Callback URL", + 29: "Non-Whitelisted Destination", + 32: "Signature And API Secret Disallowed", + 33: "Number De-activated", + } + + // https://developer.vonage.com/messaging/sms/guides/delivery-receipts#dlr-error-codes + dlrErrorCodes = map[int]string{ + 1: "Unknown", + 2: "Absent Subscriber - Temporary", + 3: "Absent Subscriber - Permanent", + 4: "Call Barred by User", + 5: "Portability Error", + 6: "Anti-Spam Rejection", + 7: "Handset Busy", + 8: "Network Error", + 9: "Illegal Number", + 10: "Illegal Message", + 11: "Unroutable", + 12: "Destination Unreachable", + 13: "Subscriber Age Restriction", + 14: "Number Blocked by Carrier", + 15: "Prepaid Insufficient Funds", + 16: "Gateway Quota Exceeded", + 50: "Entity Filter", + 51: "Header Filter", + 52: "Content Filter", + 53: "Consent Filter", + 54: "Regulation Error", + 99: "General Error", + } ) func init() { @@ -85,7 +134,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } if form.ErrCode != 0 { - clog.Error(courier.ErrorServiceSpecific("vonage", strconv.Itoa(form.ErrCode), "")) + clog.Error(courier.ErrorServiceSpecific("vonage", "d"+strconv.Itoa(form.ErrCode), dlrErrorCodes[form.ErrCode])) } status := h.Backend().NewMsgStatusForExternalID(channel, form.MessageID, msgStatus, clog) @@ -183,9 +232,10 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } nexmoStatus, err := jsonparser.GetString(respBody, "messages", "[0]", "status") + errCode, _ := strconv.Atoi(nexmoStatus) if err != nil || nexmoStatus != "0" { // https://developer.vonage.com/messaging/sms/guides/troubleshooting-sms - clog.Error(courier.ErrorServiceSpecific("vonage", nexmoStatus, "")) + clog.Error(courier.ErrorServiceSpecific("vonage", "s"+nexmoStatus, sendErrorCodes[errCode])) return status, nil } diff --git a/handlers/nexmo/nexmo_test.go b/handlers/nexmo/nexmo_test.go index 3bf170da6..443a8e6d4 100644 --- a/handlers/nexmo/nexmo_test.go +++ b/handlers/nexmo/nexmo_test.go @@ -56,7 +56,7 @@ var testCases = []ChannelHandleTestCase{ }, { Label: "Status delivered", - URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=delivered", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=delivered&err-code=0", ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, @@ -64,7 +64,7 @@ var testCases = []ChannelHandleTestCase{ }, { Label: "Status expired", - URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=expired", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=expired&err-code=0", ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, @@ -72,7 +72,7 @@ var testCases = []ChannelHandleTestCase{ }, { Label: "Status failed", - URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=failed", + URL: "/c/nx/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?to=2020&messageId=external1&status=failed&err-code=6", ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, @@ -169,7 +169,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Error status", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("vonage", "10", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("vonage", "s10", "Too Many Existing Binds")}, SendPrep: setSendURL, }, { @@ -200,7 +200,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("vonage", "1", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("vonage", "s1", "Throttled")}, SendPrep: setSendURL, }, } diff --git a/handlers/twiml/errors.json b/handlers/twiml/errors.json new file mode 100644 index 000000000..0dffb6e63 --- /dev/null +++ b/handlers/twiml/errors.json @@ -0,0 +1 @@ +{"22225": "From Bundle to Replace Items does not exist", "80612": "Duplicate Entry", "13000": "Conference Noun cannot be mixed with Number nouns", "11750": "TwiML response body too large", "62034": "Interconnect: No useful parameters provided.", "82001": "Function invocation resulted in StatusCode 4xx", "60616": "Lookup rate limit exceeded", "30111": "Url is blacklisted", "53628": "Room recordings deleted", "60699": "Lookup usage disabled", "82009": "Multi-valued headers not supported", "50304": "Programmable Chat: Attributes not valid JSON", "21616": "The 'From' number matches multiple numbers for your account", "13612": "Record: Invalid maxLength value", "19023": "Invalid channel type", "81002": "Unexpected event while processing Widget", "52108": "GCM/FCM device message rate exceeded", "57016": "'Topic' is empty", "30118": "Private key is invalid", "60215": "Max number of mailers per account reached", "51109": "Twilsock: Service instance is under legal hold", "80611": "Proxy Number In Active Sessions", "21227": "Headers portion of SIP URI must be fewer than 1024 chars", "21504": "RecordingSid is required.", "40114": "TaskRouter->Call", "21406": "Cannot set SmsFallbackUrl without setting SmsUrl", "51106": "Twilsock: Active product doesn't match with service instance product", "33010": "Conflicting update", "40121": "TaskRouter->Direct", "91003": "Account reached the max sink limit", "52202": "Facebook page is not connected to Twilio", "45357": "Downstream error configuring Channel.", "16026": "Participant label is in use by another participant", "22205": "Attempting to assign invalid object_sid to Bundle", "13802": "Dial: No referUrl attribute specified", "13241": "Dial->SIP: Invalid method value", "16002": "Failed to validate conference attributes", "21725": "Brand can only be updated when in FAILED state", "21244": "Maximum Number of Trunks reached", "16003": "Could not recognize conference sid or friendly name", "21602": "Message body is required", "62015": "Connection in transition", "30006": "Landline or unreachable carrier", "14233": "Dial->Conference: Invalid Timeout", "50412": "Participant proxy address is empty", "80911": "Call To Message Only Session Rejected", "30117": "Certificate cannot be parsed", "21477": "Unable to update Status for parent accounts", "50417": "Participants limit exceeded", "54011": "Invalid TTL", "30107": "Domain private certificate has not been uploaded", "70156": "Request Hash Is Invalid", "64017": "Pay: BankAccountType Parameter not supported with PaymentMethod = \"credit-card\"", "54006": "Request entity too large", "94601": "Date range is not valid", "19041": "Invalid or missing Custom Field input", "21235": "IP Access Control List Validation Error", "80308": "Session with the unique name not found.", "57013": "'Topic' is absent", "21222": "Invalid SipAuthUsername. Illegal chars", "91203": "Method Not Allowed", "22212": "Invalid End-User Type in request", "57020": "Authorization failed", "21237": "Maximum IP Addresses Reached for List", "22112": "Unable to Update Hosted Number Order Status", "53405": "Media connection failed or Media activity ceased", "30019": "Content size exceeds carrier limit", "50208": "Programmable Chat: User channel limit exceeded", "60213": "A Messaging Configuration already exists for the given country", "21229": "Invalid SIP Header. Illegal chars in header value", "19045": "Field definition type is invalid; data types that are supported are text, date, and number", "52052": "Client connection not created or closed", "32702": "Voice User-Defined Message: Invalid Content", "13234": "Dial->Conference: Invalid waitMethod", "50052": "Programmable Chat: Invalid consumption interval format", "32303": "Interconnect: Multiple SIP Dials with Interconnect Connection (TNX) SID", "15002": "Call Progress: Queue Timeout", "50205": "Programmable Chat: User unauthorized to set role", "50207": "Programmable Chat: Identity too long", "51108": "Twilsock: Service instance disabled", "22213": "Invalid Number Type in request", "22210": "Cannot create a Supporting Document with no Type", "32301": "Interconnect: Invalid Connection (TNX) SID", "53000": "Signaling connection error", "64009": "Pay: Twilio is no longer authorized to initiate transactions on your behalf.", "53203": "The maximum number of published tracks allowed in the Room at the same time has been reached", "50054": "Programmable Chat: Invalid webhook format", "90009": "The message SID already exists.", "64016": "Pay: Invalid Action URL", "50074": "Global actions per second limit exceeded", "80623": "Duplicate Participant Request", "92008": "Unsupported Content Type", "94403": "Transcriptions: Invalid encryption credentials", "83602": "Request StartTime and/or EndTime must be aligned to UTC hour boundaries.", "52211": "Too many Alexa notifications", "52102": "Invalid GCM/FCM registration token", "21302": "Approaching application creation limit ", "20011": "Invalid TLS version", "40142": "Failed to issue Conference instruction due to missing 'call_sid' or 'outbound_to' properties", "51113": "Twilsock: Product usage is not enabled", "90007": "Invalid validity period value", "21402": "Invalid Url", "30124": "MessagingServiceSID cannot be empty or null", "13616": "Record: playBeep must be true or false", "31429": "Too Many Requests", "70252": "Bad Saml Response", "13801": "Refer not allowed on non-SIP call legs", "14220": "Enqueue: Provided Workflow was not a valid sid", "50384": "Initial state can't be 'closed", "70105": "Invalid Type Specified in the Request", "31904": "Stream - WebSocket - Host Unreachable", "50434": "Participant projected address not provided", "60312": "Challenge creation limit reached", "50509": "Programmable Chat: Media message body cannot be updated", "64002": "Pay: Service unavailable.", "13618": "Record: Recording not available for transcription", "94400": "Transcriptions: transcription internal error", "14236": "Dial->Conference: Invalid ReservationSid", "21475": "Unable to update Status, invalid Status.", "54201": "Map Item not found", "63016": "Failed to send freeform message because you are outside the allowed window. If you are using WhatsApp, please use a Message Template.", "48028": "Outgoing conversation: Unauthorized use of the proxy address", "13310": "Gather: Invalid finishOnKey value", "90403": "[Autopilot] Signature validation failed", "31922": "Stream - WebSocket - URL Schema Not Supported", "19035": "Invalid page size, it must be between 1 and 25 if specified", "53112": "Status is invalid", "16020": "Conference is full", "60704": "Phone number not branded by Twilio", "62028": "Interconnect: Connection expired.", "31901": "Stream - WebSocket - Connection Timeout", "50451": "One user identifier parameter for lookup at a time is allowed. Please, use either Identity or Address.", "21654": "ContentSid Required", "21702": "The Messaging Service is not available to send new messages", "31940": "Stream - Invalid connectorName attribute in TwiML.", "17000": "Forbidden to access data", "60606": "Package not enabled", "22122": "Invalid Authorization Document Status", "13328": "Gather: Invalid maxSpeechTime value", "13332": "Gather: Invalid bargeIn value", "64011": "Pay: Connector does not support the requested currency.", "52143": "The push notification was rejected by APNs", "19026": "Maximum number of channels allowed reached", "64005": "Pay: Connector does not support tokenization.", "13335": "Gather: speechTimeout auto cannot be used with model default", "45351": "Invalid Channel Participant properties.", "21628": "Address Validation Error", "31952": "Stream Extension not found: ", "21456": "Invalid CallbackUrl", "52171": "Webhook Credentials request signature was not verified", "40143": "TaskRouter->Conference", "34004": "Error during fax transmission", "60318": "Factor is unverified", "20101": "Invalid Access Token", "30409": "This message cannot be canceled", "83603": "The maximum allowed query period is 31 days for group by sim queries", "22118": "Invalid Verification Document SID", "63036": "The specified phone number cannot be reached by RBM at this time.", "32017": "PSTN: Carrier blocked call due to calling number (caller ID)", "30119": "Certificate and private key pair is invalid", "68006": "Initialization Error", "16099": "Unexpected conference status", "40001": "Could not parse Assignment Instruction response as JSON. Ensure your JSON is not escaped", "32701": "Voice User-Defined Message: Invalid Content-Type", "13330": "Gather: Invalid hints value", "50059": "Programmable Chat: Notification sound name too long", "51107": "Twilsock: Service can't be used", "60407": "Authentication Token Error", "45376": "Failed to add a participant. Conversation was closed or not found.", "83003": "The Super SIM already belongs to the requesting Account.", "31409": "Conflict", "22217": "Missing Supporting Document field", "21606": "The 'From' phone number provided is not a valid message-capable Twilio phone number for this destination.", "63031": "Channels message cannot have same From and To", "13111": "Annotate: Annotate must contain only one of element X", "21233": "Domain still has subdomains", "30447": "Toll Free verification rejection - Phone Number Error", "60306": "Invalid Request", "20409": "Conflict", "53102": "Room name contains invalid characters", "19033": "Location validation error", "16102": "Voice Recording: Unavailable because recording is silent", "50431": "Participant SID not provided", "50375": "TimeToInactive should be greater or equal to 1 minute", "94402": "Transcriptions: Encryption failed and transcription result files deleted", "90002": "Too Many Errors", "19053": "Field definition name cannot be a duplicate of an existing Twilio-defined field", "54155": "List Item revision mismatch", "33101": "Invalid Parameter Value\t", "34003": "Callee did not answer", "31009": "Transport error", "80619": "Chat Channel Attribute Error", "16101": "Voice Recording : Unavailable because duration is too short", "23004": "Message Redaction Incompatible Configuration: Advanced Opt-Out", "20162": "A conflicting resource update is in progress", "80403": "Interaction Sid Invalid", "15004": "Action Callback URL must be an absolute URL when using TwiML to update in-progress calls", "45308": "Add Participant Not Allowed", "54451": "Invalid 'Order' query parameter", "11751": "Media Message - Media exceeds messaging provider size limit", "20157": "Expiration Time Exceeds Maximum Time Allowed", "53104": "Unable to connect to Room", "19028": "Channel value can not be updated", "30444": "Toll Free verification rejection - High Risk", "50380": "TimeToClosed format is invalid", "13804": "AddOns are not supported in this realm", "21623": "Number of media files exceeds allowed limit", "19012": "When updating a contact at least one field should be updated", "60218": "SendGrid Template is not active", "16106": "Voice Recording: Unavailable due to internal encryption error", "60002": "End User Identification Timeout", "45731": "Pre-engagement data too large. ", "45601": "Custom Flex UI error", "62200": "Provisioning failure - Network-API is unavailable!", "62001": "Invalid SID", "31103": "Length of parameters cannot exceed MAX_PARAM_LENGTH.", "30440": "Toll Free verification rejection - Unknown Error", "61001": "Add-ons: Request timed out", "60310": "Factor verification attempts reached", "21242": "Maximum Credentials Reached for List", "32019": "Twiml and Voice URL are both set. Using Voice URL.", "32102": "SIP: Bad SDP", "90015": "Body and Template (Body, Sid, Language, Args) are provided", "30121": "Fallback URL is missing", "62005": " Bandwidth reserve not found.", "21611": "This 'From' number has exceeded the maximum number of queued messages", "52131": "Invalid APNs credentials", "60004": "Invalid Configuration ", "21263": "Invalid Answering Machine Detection Parameters", "51110": "Twilsock: Token contains multiple grants of same product", "40120": "TaskRouter->Direct", "31502": "Bad Gateway", "31206": "Rate exceeded authorized limit.", "16011": "Conference Event: Error Response to Callback URL", "30027": "US A2P 10DLC - T-Mobile Daily Message Limit Reached", "45356": "Failed to create a channel. Downstream error.", "22223": "Regulatory Bundle is not eligible to be Copied", "13420": "Play: Invalid Content-Type", "48005": "Callback failed due to timeout", "63008": "Could not execute the request because the channel module has been misconfigured. Please check the Channel configuration in Twilio", "90104": "Invalid Collect Field Type", "30112": "Account is not found", "34108": "Other End Incompatible", "33004": "Service is unavailable\t", "33102": "Parameter missing", "23002": "Message Redaction Incompatible Configuration: Short code \"STOP\" filtering", "30011": "MMS not supported by the receiving phone number in this region", "30130": "Messaging Service SID already belongs in another domain configuration.", "53408": "ICE connection restart was attempted, but it is not allowed", "54351": "Invalid identity", "51114": "Twilsock: Invalid access token header", "22114": "Unable to Verify Code", "21407": "This Phone Number type does not support SMS", "21627": "Max Price must be a valid float", "21457": "AreaCode Parameter not Supported", "23005": "Phone Number Redaction Incompatible Configuration: Fallback to Long Code", "90014": "Validity Period should be positive integer", "60211": "Bucket with the given Interval already exists", "80607": "Session Closed", "51004": "Client Connection: endpoint_id too long", "50449": "Conflicting channel modification", "81026": "Studio Execution failed because Flow exceeds maximum allowed widgets", "22111": "Invalid Hosted Number Order Status", "94303": "Transcriptions Configurations: Language is required", "60324": "Challenge verification failed", "92005": "ContentSid Required", "40130": "TaskRouter->Dequeue", "53106": "Room not found", "21408": "Permission to send an SMS has not been enabled for the region indicated by the 'To' number", "54156": "Invalid List Item data", "54450": "Invalid 'Direction' query parameter", "45309": "Modify Participant Not Allowed", "45373": "Failed to remove Participant. Internal error.", "31408": "Request Timeout", "53616": "Deleted a recording with custom configuration as time for retries was depleted", "52133": "Invalid APNs device token size", "35125": "Maximum limit reached in the account for scheduling messages", "53301": "Track name is invalid", "52163": "Incorrect URL used to retrieve Webhook Credentials", "51118": "Twilsock: Invalid claim set", "60205": "SMS is not supported by landline phone number", "21607": "The 'from' phone number must be the sandbox phone number for trial accounts.", "21204": "Call already initiated", "60519": "SNA Verification Result Pending", "19057": "Server unavailable or busy", "21712": "Phone Number or Short Code is associated with another Messaging Service.", "91004": "Test event cannot be found", "19029": "When updating a channel at least one field should be updated", "81007": "Connecting to a Call timed out", "13230": "Dial->Conference: Invalid muted value", "21102": "Reached maximum number of Services", "20159": "Invalid Signature", "13222": "Dial->Number: Invalid sendDigits value", "50057": "Programmable Chat: Webhook call failed to execute successfully", "40138": "Missing 'from' parameter when issuing Conference instruction", "93104": "There is an issue with the Kinesis Stream Name or Region", "57006": "'EventType' is empty", "63041": "Template paused", "45101": "Configuration Not Found", "53300": "Track is invalid", "32112": "SIP: Invalid header value", "64018": "Pay: Value needed for either Capture or Status parameters", "57007": "'EventType' is absent", "53601": "AWS credentials for recording upload are invalid", "60620": "Lookup SIM Swap Information is Not Available From Carrier", "20004": "Method not allowed", "13617": "Record: Recording length is out of range for transcription", "52162": "Credentials do not belong to used account", "21257": "Invalid SIP Manipulation Policy SID", "45711": "Failed to create webchat participant. Unauthorized ", "21650": "Phone Number Requires a Verified Identity Document", "30108": "Twilio account does not belong to an organization", "10003": "Incoming call rejected due to inactive account", "19014": "Can fetch contact either by unique_customer_provided_id or channel ", "54251": "Invalid Message Stream Message data", "50340": "Messaging service SID not provided", "53404": "No supported codec", "60229": "Template translation was not found", "16023": "Dial->Conference: Invalid participant label, must not exceed 128 characters, must not be a CallSid, must not contain '/'", "53620": "Invalid URL for external S3 bucket in composition settings", "21403": "Invalid Method", "21253": "Max Connection Policies Reached", "21473": "AccountSid you are transferring to is not related to the originating owner of the phone number", "90030": "Broadcast 'CorrelationId' is too long", "53627": "Internal failure when updating the composition resource", "32208": "SIP: Secure media required", "19022": "Invalid channel", "45362": "Failed to remove Participant. Not found.", "14213": "Dial->Queue: queue name too long", "21478": "Unable to update Status for subaccount, subaccount has been suspended by Twilio", "60614": "Lookup package not supported in region", "31209": "Call Message Event Payload size exceeded authorized limit.", "53215": "Invalid Subscribe Rule(s)", "50377": "Can't update conversation as it's in final closed state", "52103": "GCM/FCM client uninstalled or turned off notifications", "32219": "SIP: Redirect failed", "30016": "'To' and 'From' channel types are incompatible", "50506": "Programmable Chat: Media SID not provided", "20422": "Invalid Parameter", "53204": "Participant not found", "50101": "Programmable Chat: Channel role not found", "13805": "Trial account call duration exceeded 10 minute limit", "91101": "Subscription could not be created", "45374": "Failed to delete Channel. Internal error.", "57009": "'EventType' is too long", "20105": "Access Token not yet valid", "21248": "Trunk Domain already taken", "60005": "Downstream Carrier Error", "53621": "Invalid AWS credentials to access external S3 bucket in composition settings", "50332": "Programmable Chat: Channel webhook url too long", "30022": "US A2P 10DLC - Rate Limits Exceeded", "80306": "Not Found Chat Service", "50393": "Type value should be 'private'.", "21218": "Invalid ApplicationSid", "16022": "Conference does not exist or is completed", "20404": "Not Found", "20021": "Phone number rejected by T-Mobile SDG Service Provisioning API", "40135": "TaskRouter->Dequeue", "30100": "Domain SID is invalid", "90027": "Broadcast 'FriendlyName' is too long", "30002": "Account suspended", "64010": "Pay: Payment Gateway rejected token creation.", "16025": "Dial->Conference: Participant label is in use by another participant", "80606": "Proxy Identifier Not Owned By Account", "14204": "Enqueue: Queue name too short", "53617": "Internal failure when bulk deleting compositions from your account", "50436": "Participant limit exceeded for group conversation", "81014": "There was an internal error while processing an HTTP request", "13331": "Gather: Invalid language value", "94304": "Transcriptions Configurations: Language is invalid", "83001": "Parameter missing while registering a Super SIM", "92007": "The Content Variables Parameter is invalid", "21723": "Campaign Verify token import already in progress", "13252": "Dial: Invalid header name", "40152": "Invalid Queue for Known Worker", "50374": "'State' field can't be empty", "54100": "Document not found", "53208": "Participant's bandwidth profile configuration is invalid", "21207": "Invalid IfMachine", "80904": "Expired Session", "30446": "Toll Free verification rejection - Opt-In Error", "40005": "Assignment Callback response does not contain Instruction", "21503": "Invalid transcription type", "30009": "Missing inbound segment", "50330": "Programmable Chat: Channel webhook filter not provided", "70004": "Unauthorized", "81012": "Failed to update Sync service", "50382": "Timer can't be set without state", "13212": "Dial: Invalid timeout value", "60500": "SNA Phone Number Mismatch", "53205": "Participant disconnected because of duplicate identity", "63028": "Number of parameters provided does not match the expected number of parameters", "21472": "Account is not active", "21203": "International calling not enabled", "45207": "Chat User per Chat Channel limit reached. User is part of too many Chat Channels.", "51105": "Twilsock: Token doesn't contain identity", "60611": "Lookup quota reached", "90103": "Error processing answer during collection", "50418": "Non-Chat participants limit exceeded", "81019": "Twilio phone number using deprecated API version", "21701": "The Messaging Service does not exist", "21239": "Maximum Credential Lists Reached", "50378": "'State' parameter value is invalid", "51201": "Twilsock : CPS, Init per Account", "62017": "No IP route specified", "50438": "Group conversation with given participant list already exists", "60619": "Lookup Request Cannot be Completed in Twilio Region", "30116": "Certificate or private key or both are missing", "60401": "Network Error", "20423": "Invalid SID", "14221": "Enqueue: Provided Attributes JSON was not valid", "11243": "HTTP retry policy is invalid", "64019": "Pay: Required payment information incomplete", "17009": "Internal Server Error", "48031": "Outgoing conversation: Conversation with this contact and proxy address already exists", "45700": "Unexpected error occurred. Unable to process WebChat request.", "60410": "Verification delivery attempt blocked", "13611": "Record: Invalid timeout value", "20012": "Invalid TLSv1.2 Cipher Suite", "62006": " MPLS carrier is not associated with the exchange.", "34106": "No Fax TwiML action specified", "64006": "Pay: Connector does not support token type.", "32021": "SHAKEN/STIR call verification failed", "33119": "SIM connectivity reset not allowed", "31604": "Does Not Exist Anywhere", "32500": "Voice Conversation: Generic error.", "32101": "SIP: Invalid phone number", "64014": "Pay: ECP/ACH requires AVSName Parameter in the verb.", "19056": "Input request content type is invalid", "80504": "An internal server error has occurred.", "22401": "Phone Number Instance fields are not supported within region", "17001": "Completed summary for this call wasn't found", "90016": "'Template' or 'TemplateSid'/'TemplateLanguage' is required to send a Template Message", "50107": "Programmable Chat: User not authorized for command", "53109": "Timeout is out of range", "63001": "Channel could not authenticate the request. Please see Channel specific error message for more information", "62003": "MPLS carrier not found.", "32009": "The user you tried to dial is not registered with the corresponding SIP Domain", "50201": "Programmable Chat: User already exists", "90006": "Invalid direction", "22200": "Invalid End-User Type or Number Type", "64004": "Pay: Invalid paymentConnector attribute in TwiML.", "60604": "SendGrid Authenticated user is not authorized to send mail", "83002": "Super SIM cannot be registered", "60311": "Factor verification failed", "52164": "No Credentials found for the supplied Binding Type", "21501": "Resource not available", "30122": "Fallback URL is invalid", "33108": "Rate Plan not found", "57018": "'Event' value type must be Map", "50328": "Programmable Chat: Channel webhook type not provided", "60517": "SNA User-Agent Mismatch Error", "57003": "'Secret id' is invalid for this Partner", "54003": "Invalid If-Match header", "80802": "Simultaneous requests to create the same Identifier in one or more Sessions", "22102": "Invalid Phone Number", "83007": "Unable to activate your Super SIM as it does not belong to a Fleet", "19010": "Invalid contact search request", "32209": "SIP: Secure transport required", "80614": " No Partner Participant Found", "12301": "Invalid Upload Content-Type", "50104": "Programmable Chat: Permission not found", "31002": "Connection declined.", "13247": "Dial: Invalid From number (caller ID)", "48029": "Outgoing conversation: Contact address type does not match proxy address type", "45103": "Workspace Not Configured", "50309": "Programmable Chat: Invalid Date Updated parameter", "80602": "Non Unique Service Name", "20500": "Internal Server Error", "54509": "Query expression contains too many operators", "45361": "Failed to add Participant. Downstream error.", "90102": "Assistant failure to start collection", "90013": "'Template' or 'TemplateSid'&'TemplateLanguage' or 'MediaUrls' is required", "83605": "StartTime parameter is too far in the past. It must be within the last 18 months.", "53661": "StatusCallbackMethod is invalid", "21620": "Invalid media URL(s)", "48011": "Custom Routing Callback failed due to an internal error", "14238": "Dial->Conference: Unable to accept Reservation", "13257": "Invalid transcribeCallback URL", "31202": "Signature validation failed.", "30031": "Invalid MaxRate", "51003": "Client Connection: identity too long", "82006": "Environment Context too large", "60723": "Brand status does not allow updates", "33201": "Unauthorized", "32503": "Voice Conversation: Callback event response error.", "80903": "Unknown Participant", "21648": "Regulatory Bundle cannot be deleted due to active number assignment", "21608": "The 'to' phone number provided is not yet verified for this account.", "57004": "'Category' is empty", "94500": "Transcriptions: sourceSid invalid", "60612": "Requested phone number not mobile", "13329": "Gather: Invalid partialResultCallbackMethod value", "50363": "Invalid conversation webhook SID", "60712": "Error communicating with Regulatory Compliance API", "21220": "Invalid call state", "60621": "Lookup SIM Swap Information is Incomplete From Carrier", "503": "Internal Error", "32601": "Virtual Agent: Provider Error", "50414": "Participant address type does not match proxy address type", "60719": "Branded Call not found", "45719": "Failed to create webchat participant. Too many requests ", "70052": "Public Key Client Validation Required For Account", "21614": "'To' number is not a valid mobile number", "13233": "Dial->Conference: Invalid waitUrl", "91007": "Sink still in use", "21613": "PhoneNumber Requires Certification", "60602": "App hash can only be used with SMS channel", "58000": "Twilio Live congestion", "63023": "Channel generic error", "21502": "Invalid callback url", "21231": "Domain Validation Error", "51130": "Twilsock: Token is invalid!", "60212": "Too many concurrent requests for phone number", "31920": "Stream - WebSocket - Handshake Error", "62025": "Interconnect: Invalid connection type", "19044": "Field definition name exceeded maximum length", "51116": "Twilsock: Invalid access token grants", "50310": "Programmable Chat: Author parameter is too long", "80208": "No Available Unused Proxy", "51006": "Client Connection: Connection expired", "45003": "Authorization Error", "21101": "Subaccounts cannot contain subaccounts", "60208": "Rate limit with that UniqueName already exists", "62012": "Connection not found.", "52137": "Invalid size of subject in APNs certificate", "17007": "Voice Insights Advanced Features not enabled", "91006": "The sink sid is in an invalid format", "70104": "Invalid Public Key", "13333": "Gather: Invalid profanityFilter value", "50452": "Group MMS is not enabled for this Account", "45307": "Add Participant Not Allowed", "33111": "Command exceeded max length", "52145": "Failed to authenticate with APNs", "60721": "Phone Number(s) already used in a Branded Channel", "53120": " Invalid Recording Rule(s)", "80301": "Not Found Phone Number SID", "83008": "Unable to remove your Super SIM from its Fleet", "13313": "Gather: Invalid timeout value", "83010": "Unable to update your Super SIM to the desired status", "20007": "Page size too large", "90017": "'Template' and 'TemplateSid'/'TemplateLanguage' must not be specified together", "62053": "Interconnect: The subaccount is not authorized to access this connection. ", "50371": "Conversation webhook trigger not provided", "21709": "Alpha Sender ID is Invalid or Not Authorized for this Messaging Service", "11202": "TCP connection refused", "31530": "DNS Resolution Error", "83703": "Attachment Rejected Due To Rate Limiting", "83500": "No eSIM Profiles are available", "14101": "Invalid \"To\" attribute", "50373": "No Messaging Service assigned to Conversation", "30012": "TTL is too small", "53006": "Video server is busy", "50442": "Failed to remove the projected address of a participant.", "80101": "Number Already Added to Another Service", "19046": "Number of custom field definitions exceeded limit", "91005": "Test ID is invalid", "94200": "Transcriptions Settings: Invalid encryptionEnabled value", "21201": "No Called number specified", "30445": "Toll Free verification rejection - Invalid Information", "13227": "Geo Permission configuration is not permitting call", "21722": "Invalid Campaign Verify token", "80617": "Flex Configuration Error", "50370": "Conversation webhook filter not provided", "32007": "SIP: Too many endpoints/bindings for the Address-of-record (AOR)", "13510": "Say: Invalid loop value", "50511": "Invalid message media content type", "50327": "Programmable Chat: Invalid channel webhook flow sid", "20154": "Invalid Claim Set", "50211": "Identity parameter not acceptable for this Participant", "90010": "Account is not active", "45355": "Failed to create a channel. No Participants found.", "50602": "Programmable Chat: Cannot decline invite when already channel member.", "45371": "Failed to close Channel. Internal error.", "60003": "End User Data is Not Available", "60727": "Channel not found", "31104": "Invalid bridge token.", "53002": "Signaling connection timed out", "13614": "Record: Invalid transcribe value", "19055": "When updating a channel, invalid JSON syntax or invalid field that cannot be updated by this endpoint", "50437": "Group Participant already exists", "40140": "Failed to issue Dequeue instruction due to missing 'call_sid' property", "50051": "Programmable Chat: Service SID not provided", "63038": "Account exceeded the daily messages limit", "83705": "Attachment Rejected Due To SIM In Inactive State", "45762": "Failed to validate address configuration. Auto create type is empty or invalid. ", "53207": "MaxPublishedTracks is out of range", "50408": "Invalid participant proxy address", "54103": "Document revision mismatch", "50440": "Failed to remove the proxy address of a participant.", "70155": "Request Is Missing Required HTTP Headers", "50351": "Conversation SID not provided", "50213": "Conflicting user modification", "90037": "Broadcast has too many 'CorrelationId' items", "31208": "User denied access to microphone.", "60532": "SNA Potential Dual SIM Detected", "14230": "Dial->Conference: Invalid WorkflowSid", "57002": "'Secret id' is too long", "31910": "Stream - WebSocket - SSL Protocol Error", "83005": "Super SIM not found", "63020": "Twilio encountered a Business Manager account error", "50100": "Programmable Chat: Role not found", "52001": "Invalid destination binding", "53113": "Room creation failed", "60706": "Invalid Push Token", "21226": "SIP calling not enabled for this account", "20107": "Invalid Access Token signature", "32202": "SIP: Bad user credentials", "50369": "Conversation webhook URL not provided", "21255": "Maximum IP Access Control Lists reached", "83700": "Attachment Failed Due To Internal Error", "16024": "Invalid participant label, must not exceed 128 characters, must not be a CallSid, must not contain '/'", "80206": "No Available Proxy", "34002": "Callee Busy", "19011": "When updating a contact, invalid JSON syntax or invalid field that cannot be updated by this endpoint", "19031": "Maximum number of locations allowed reached ", "94401": "Transcriptions: audio processing error", "60709": "Business Profile already exists", "22402": "Phone Number Operation not permitted within Region", "91000": "Sink could not be created", "52109": "GCM/FCM unauthorized error", "62020": "Connection pending deletion.", "70001": "Validation Failed", "63035": "This operation is blocked because the RBM agent has not launched and the recipient has not been invited and accepted the invitation to become a tester.", "17008": "Internal Server Error - Query Timeout", "83011": "A Super SIM with the specified Unique Name exists already", "32106": "SIP: Authentication Error", "90041": "Broadcast 'MediaUrl' field is too long", "50516": "Programmable Chat: Message index is not a number", "32014": "Call is terminated because of no audio received", "80906": "Interaction Not Open", "50204": "Programmable Chat: Identity not provided", "51125": "Twilsock: Too many updates", "13226": "Dial: Invalid country code", "70251": "Bad SSO Settings", "63011": "Invalid Request: Twilio encountered an error while processing your request", "35112": "OptimizeStartAt timestamp is missing", "20155": "Expiration Time In The Future", "11100": "Invalid URL format", "21409": "VoiceCallerIdLookup cannot be set for this phone number", "92004": "Invalid language code", "30133": "The certificate could not be uploaded.", "52172": "Unexpected Binding Type used for Webhook Credentials request", "14217": "Dial->Queue: Could not find or accept provided reservationSid", "21422": "PhoneNumber is not available", "51126": "Twilsock: DNC limit has been reached", "32006": "SIP: Too many hops", "45203": "Requested Chat User not found", "21630": "Cannot mutate Address that is linked to a verified Document.", "50416": "Participant and proxy address pair is already in use", "19027": "Invalid Channel Description", "60609": "Live activity not enabled", "60408": "TemplateSid is only supported for the SMS channel", "45744": "Failed to create webchat conversation. A resource provided could not be found. ", "21720": "A2P Use Case is Invalid", "13615": "Record: maxLength too high for transcription", "11242": "HTTP connection over Twilio Interconnect is not allowed", "19021": "Only one channel can be set as primary", "52104": "Mismatched GCM/FCM sender ID", "13326": "Gather: Invalid input value", "31426": "Upgrade Required", "57011": "Unsupported Partner name", "50053": "Programmable Chat: Invalid typing indicator format", "50513": " Message author should be among Group MMS participants.", "21211": "Invalid 'To' Phone Number", "60323": "Challenge expired", "50419": "Conflicting member modification", "53632": "Failed to enqueue a room composition", "45109": "Skills Limit Exceeded", "50413": "Account is not authorized to use proxy address", "21705": "The Messaging Service is invalid", "13750": "Twiml verb not supported by this API version.", "45010": "Rate Limit Exceeded", "13240": "Dial->Conference: Invalid Whisper SID", "52004": "Credential SID not specified", "16110": "Internal failure when bulk deleting recordings from your account", "53103": " Unable to create Room", "13610": "Record: Invalid method value", "32205": "SIP Trunking: Geo Permission configuration is not permitting call", "81025": "Studio Flow exceeds maximum allowed widgets", "45206": "Chat User is already a member of the Chat Channel", "21703": "The Messaging Service does not have a phone number available to send a message", "40157": "Dequeue Instruction does not have a valid 'status_callback_url' parameter", "50362": "Too many conversation webhook triggers", "21236": "IP Access Control List Dependencies Violation", "13220": "Dial: Invalid ringTone value", "21449": "Number already can be used for outgoing calls and messages", "45701": "Unexpected error occurred. Service unavailable. ", "21604": "The destination 'To' phone number is required to send an SMS", "50320": "Programmable Chat: Channel webhook not found", "54101": "Invalid Document data", "60411": "Phone Number already exists", "19030": "Invalid location type", "94002": "Transcriptions: configuration not found", "21252": "Invalid Region", "30400": "Parameters are not valid ", "32216": "SIP: Address blacklisted", "19032": "Invalid location input", "60209": "UniqueName format is invalid", "80105": "Short Code Already In Service", "22215": "Missing End-User field", "68002": "Mapper Error", "45367": "Failed to add Participant. Invalid request parameters.", "32016": "PSTN PDD timeout", "21301": "Cannot create application: application limit exceeded", "60325": "Translation for locale not found, using default", "13910": "Pause: Invalid length value", "60221": "No target verification specified", "31504": "Gateway Timeout", "21605": "Maximum body length is 160 characters (old API endpoint)", "52071": "Internal error when sending notification via mqtt client connection", "52105": "Invalid GCM/FCM package name", "53668": "Public key credentials for media tracks encryption could not be loaded", "53001": "Signaling connection disconnected", "80407": "Phone Number Sid Invalid", "31930": "Stream - Media - Buffer Overflow", "13246": "Dial: SIP dialing not enabled for this account", "21612": "The 'To' phone number is not currently reachable via SMS", "53206": "The Participant concurrency quota was exceeded", "32207": "SIP: Secure media not accepted", "60315": "Reached max limit of 20 push Factors associated per Entity", "32103": "SIP: Empty body", "70102": "Unsupported Public Key Length", "57017": "'Topic' is too long", "40137": "Missing 'to' parameter when issuing Conference instruction", "81017": "Error in Twilio Function Response", "53123": "MaxParticipantDuration is out of range", "90032": "Broadcast recipient's 'to' is invalid", "81006": "Failed to create Chat Channel", "50202": "Programmable Chat: User SID not provided", "11236": "Certificate Invalid - Certificate Expired", "52213": "Invalid Alexa user ID", "80913": "Out-Of-Session Callback Error", "81005": "Failed to transition because no match was found", "52167": "Invalid Webhook Credentials response", "14202": "Enqueue: Invalid waitUrl", "32603": "Virtual Agent: Unsupported attribute(s) in TwiML", "62021": "IP Gateway Invalid", "21619": "Unable to create record", "20153": "Invalid Issuer Or Subject", "53626": "Internal failure while processing media composition", "60404": "Input Error", "53664": "Invalid URL for external S3 bucket in composition settings", "50105": "Programmable Chat: Invalid role type", "30007": "Message filtered", "22403": "Phone Number Operation not permitted within Region", "22400": "Phone Number linked to Active Route Configuration", "50058": "Programmable Chat: Notification template too long", "14111": "Invalid To phone number for Trial mode", "63006": "Could not format given content for the channel. Please see Channel specific error message for more information", "80502": "Internal Server Error from Downstream", "63029": "The receiver failed to download the template", "52311": "Delivery callback invocation failed", "93101": "Unable to deliver events to sink", "20156": "Expired or Invalid Expiration in Token", "45208": "Chat Channel with this unique name already exists", "70051": "Authorization Failed", "54507": "Invalid query", "60534": "SNA Downstream Carrier Error", "62009": "Account SID was not found.", "19048": "Input request body is not properly json formatted", "40147": "Failed to issue Supervise instruction due to missing or invalid 'contact_uri' property", "17002": "This call ended more than 30 days ago", "62024": "Missing connection type", "53202": "Participant identity contains invalid characters", "21210": "'From' phone number not verified", "58001": "Video-enabled PlayerStreamer concurrency quota was exceeded", "35126": "The ScheduleType value provided is not supported for this channel", "45370": "Failed to create outbound Channel. Internal error.", "80303": "Not Found Short Code Sid", "52214": "Alexa skill is not connected to Twilio", "80905": "Unknown Scenario", "60716": "Selected logo is not a valid PNG file", "61004": "Add-ons: No results", "52304": "User already exists", "45358": "Failed to close Channel. Missing status parameter.", "50422": "Non-chat conversation participants limit exceeded", "45005": "Service Unavailable", "35111": "SendAt timestamp is missing", "13217": "Dial: Invalid record value", "80503": "No Records Updated", "50003": "Programmable Chat: Friendly name too long", "60702": "Business Profile not found", "83402": "Received error response to IP Command callback request", "60223": "Delivery channel disabled", "30103": "Links not shortened due to shortener application failure", "11320": "Invalid template unclosed brackets", "21249": "Maximum Origination URIs reached ", "13242": "Dial->SIP: Invalid sendDigits value", "13245": "Dial: Not allowed in this API version", "53304": "Track name is duplicated", "52140": "Unknown APNs error", "22224": "Regulatory Bundle cannot transfer Item Assignments", "30105": "Shortened link not found and no fallback URL found", "51104": "Twilsock: Token doesn't contain service instance", "45360": "Failed to close or delete Conversation. Downstream error.", "52215": "Missing Title parameter for Alexa", "22207": "Unable to parse attributes JSON", "21256": "Invalid ruleset", "32008": "SIP: Registration per second limit reached", "60510": "SNA Error", "51122": "Twilsock: Authentication failed", "20104": "Access Token expired or expiration date invalid", "20020": "No update/state change is observed for the data entered", "52182": "Messaging Service not specified", "21710": "Phone Number Already Exists in Messaging Service", "30404": "Not Found", "53622": "Invalid public key for media tracks encryption in composition settings", "54053": "Invalid friendly name", "57005": "'Category' is too long", "19042": "Custom Field validation error", "54452": "Invalid 'Bounds' query parameter", "12101": "Invalid Twilio Markup XML version", "14211": "Dial->Queue: Invalid whisper url", "30129": "Certificate is self signed", "45733": "Pre-engagement data is not in valid JSON format.", "32711": "Voice User-Defined Message: Request to subscription callback URL encountered error ", "58003": "Audio-only PlayerStreamer concurrency quota was exceeded", "21452": "No phone numbers found in area code", "16010": "Conference Event: Internal Twilio Error", "33107": "SIM not found", "50324": "Invalid channel webhook type", "50421": "Invalid last read message index format", "61000": "Add-ons: Internal server error", "21421": "Phone Number is invalid", "30127": "MessagingServiceSID is invalid.", "21259": "Maximum number of SIP Manipulation Polies per account reached", "33000": "Generic Error", "53669": "Access denied to external S3 bucket configured in composition settings", "83000": "Super SIM registration failed due to Internal Error", "16108": "Voice Recording: Request failed due to concurrent recordings", "50361": "Too many conversation webhooks", "21902": "InvoiceTag length must be between 0 and 32", "13312": "Gather: Invalid method value", "22204": "Bundle status and properties cannot be updated in the same request", "20429": "Too Many Requests", "22113": "Phone Verification Incorrect", "30441": "Toll-Free phone number verification rejection - Content Violation", "22203": "Unable to parse bundle status", "50364": "Invalid conversation webhook type", "30128": "MessagingServiceSidsAction is invalid", "13521": "`` element character limits exceeded", "50068": "Programmable Chat: Service instance unique name invalid", "60228": "Template was not found", "51202": "Twilsock : CPS, Too many requests", "16113": "Voice Recording: Cannot download a dual-channel presentation of a mono recording", "15009": "Internal Server Error", "53217": "maxAudioTracks or maxVideoTracks configuration is out of range", "83702": "Attachment Rejected Due To Network Not Allowed", "60326": "Too many requests to create factors for the entity", "45002": "Authentication Error", "52149": "Invalid APNs provider token used", "22214": "Missing End User", "22209": "Invalid status enum in Supporting Document update request", "50415": "Proxy address is not WhatsApp enabled sender", "30032": "Toll-Free Number Has Not Been Verified", "32220": "Specifying an edge is not allowed when dialing SIP registered endpoints", "50212": "Programmable Chat: User already invited", "40151": "TaskRouter->Invalid instruction", "13340": "Gather: Degraded Speech ", "53501": "Unable to acquire TURN credentials", "22404": "Starter profile creation and updates are temporarily disabled", "53603": "Internal failure while processing a recording", "50600": "Programmable Chat: Invite SID not provided", "93103": "There was an error with your Kinesis stream", "54301": "Unique name already exists", "22119": "Invalid Capabilities", "21471": "Account does not exist", "70253": "Invalid User Grants", "90012": "'Recipients' list has too many items", "17400": "Invalid query parameter", "81016": "Outbound HTTP Request Failed", "21601": "Phone number is not a valid SMS-capable inbound phone number", "32218": "SIP: Transfer not allowed", "48027": "Outgoing conversation: Proxy address equals contact address", "13221": "Dial->Number: Invalid method value", "32215": "Dial failure calling a SIP Domain without specifying a region", "14212": "Dial->Queue: queue name too short", "60308": "Challenge verification attempts limit reached", "45760": "Unable to validate address configuration. Auto create data missing. ", "21910": "Invalid From and To pair. From and To should be of the same channel.", "60714": "Brand not found", "22105": "Invalid URL format", "80624": "Approaching Maximium Number Pool Size", "13251": "Dial: Too many headers passed", "53110": "StatusCallbackMethod is invalid", "54009": "Rate limit exceeded", "13430": "Play: Invalid DTMF String", "52305": "User already belongs to the segment", "54051": "Invalid webhook URL", "50203": "Programmable Chat: Identity reserved", "22005": "Call Queue Full", "52181": "Too many SMS notification requests", "80622": "Maximum Pool Size Error", "51127": "Twilsock: PNC limit has been", "80501": "Storage Operation Failed", "90003": "Unable to fetch plugins from the Custom Plugins URL", "82005": "Function execution resulted in an error log", "48025": "Outgoing conversation: Invalid contact address", "13299": "2010 Conference API feature requested using 2008 API", "22117": "Invalid Extension", "22108": "Invalid Application SID", "50056": "Programmable Chat: Webhook disabled processing of command", "50403": "Programmable Chat: Channel member limit exceeded", "52144": "APNs experienced an internal error", "31486": "Busy Here", "40134": "Dequeue Instruction does not have a valid 'status_callback_events' parameter", "10002": "Trial accounts do not support the feature you tried to use", "54354": "Permission not found", "45302": "Participant was disconnected before setting up Meeting", "82002": "Error on Twilio Function response", "33105": "Transition invalid", "57019": "'Authorization' header is missing or is invalid", "30125": "Your phone number could not be registered with US A2P 10DLC", "60317": "Factor already exists", "53500": "Unable to acquire configuration", "80618": "Chat Integration Error", "53663": "Internal failure when bulk deleting recordings from your account", "14226": "TaskRouter Enqueue not supported in this realm", "14239": "Dial->Conference: Unable to update Worker", "63025": "Media already exists", "35116": "Scheduling does not support this timestamp", "52166": "Webhook Credentials endpoint responded with Internal Error", "31008": "Call cancelled", "60202": "Max check attempts reached", "30442": "Toll-Free phone number verification rejection - Campaign Violation", "30021": "Internal Failure with messaging service orchestrator", "32001": "SIP: Trunk CPS limit exceeded", "81024": "Subflow Error", "50420": "Participant Messaging Binding type does not support all of the provided Messaging Binding parameters", "54502": "Invalid index name", "50321": "Programmable Chat: Too many channel webhooks", "13231": "Dial->Conference: Invalid endConferenceOnExit value", "40000": "Content-Type of 'application/json' not set", "62027": "Interconnect: Extra MPLS parameter", "53662": "StatusCallback is invalid", "52310": "Notification TTL has expired", "50502": "Programmable Chat: Message index not provided", "13120": "Annotate->BillingReferenceTag cannot be over 128 characters", "52309": "Channel provider replied with an error", "21653": "There are more recipient addresses than allowed", "62008": "Bandwidth reserve is not associated with the exchange.", "45375": "Failed to delete Channel. Invalid Account sid.", "82004": "Function execution resulted in a warning log", "12300": "Invalid Content-Type", "51215": "Twilsock: Unauthorized", "80604": "Proxy Identifier In Use", "32113": "SIP: Header name is not allowed", "30123": "Callback URL is missing", "21453": "Phone number already validated on another account", "35113": "OptimizeEndAt timestamp is missing", "60200": "Invalid parameter", "19024": "Invalid channel input", "81004": "Failed to add member to Chat Channel", "60713": "Error communicating with Regulatory Identification API", "45301": "Error occurred when connecting to a Meeting Participant", "19038": "Page token must be bigger than or equal to 0", "62100": "IP address(es) already linked to another connection", "48032": "Outgoing conversation: Missing Messaging service", "22222": "Emergency Status cannot be updated", "63022": "Invalid vname certificate", "11235": "Certificate Invalid - Domain Mismatch", "90025": "Template body has unsupported tag type", "50401": "Programmable Chat: Member SID not provided", "20102": "Invalid Access Token header", "40123": "TaskRouter->Redirect", "80304": "Not Found Unmanaged Identifier", "52401": "Too many notification log events ", "70106": "Invalid AWS credentials", "60707": "Branded Channel not found", "52203": "Missing body for Facebook Messenger delivery attempt", "45369": "Failed to create inbound Channel. Internal error.", "31000": "Generic error", "45366": "Failed to create Channel. Invalid request parameters.", "10001": "Account is not active", "50507": "Programmable Chat: Media not found", "31923": "Stream - WebSocket - Malformed URL", "80605": "Proxy Identifier Not In Service", "30024": "Numeric Sender ID Not Provisioned on Carrier", "14222": "Enqueue: Could not create Task", "60313": "Unauthorized factor creation", "30029": "Invalid ContentRetention", "48030": "Outgoing conversation: Proxy address is not WhatsApp-enabled sender", "50206": "Programmable Chat: Identity should not match user SID pattern", "13112": "Annotate: Invalid nested element", "62007": "Direct connect is not associated with the exchange.", "50435": "Group MMS activation failed.", "91102": "Subscription could not be found", "94100": "Transcriptions: status callback response error", "22218": "The Supporting Document field does not match the field in the End-User", "63009": "Channel provider returned an internal service error (HTTP 5xx). Please see Channel specific error message for more information", "90039": "Broadcast 'MessageStatusCallbackUrl' is invalid", "20151": "Authentication Failed", "54453": "Invalid 'PageToken' query parameter", "13327": "Gather: Invalid speechTimeout value", "30114": "Specified date is not available yet", "30003": "Unreachable destination handset", "50303": "Programmable Chat: Attributes too long", "22208": "Supporting Document status and attributes cannot be updated in the same request", "16105": "Voice Recording: Unavailable due to no valid public keys", "21209": "Invalid Method", "45763": "Unable to validate address configuration. Auto create studio flow SID missing. ", "11203": "HTTP communication total time out triggered", "63003": "Channel could not find To address", "12100": "Document parse failure", "60224": "Missing substitutions for selected template", "52165": "No Credentials found for the supplied Identifier", "22120": "Invalid Verification Type", "52135": "Missing subject in APNs certificate", "61008": "Add-ons: HTTP too many redirects", "20103": "Invalid Access Token issuer/subject", "61005": "Add-ons: Bad request", "60607": "Provider not found", "53605": "Internal failure when retrieving your account's recording settings", "14106": "Document retrieval limit reached", "16028": "Participant to be whispered is not present in the conference", "45209": "Adding a user to the Chat Channel has timed out waiting for a response from Twilio Chat.", "19054": "Expected Unique form key in input request is missing", "50379": "TimeToInactive format is invalid", "13248": "Dial: Invalid callerID, too long", "50350": "Conversation not found", "14240": "Max concurrent Workers exceeded", "94600": "Filter limit exceeded", "22206": "Attempting to add invalid object type to bundle", "54300": "Unique name not found", "13244": "Dial: No SIP Authorization", "30131": "Domain's certificate will expire soon", "14235": "Dial->Conference: Unable to cleanup task", "62019": "IP route exceeds permitted IP range", "48050": "Internal service error", "50060": "Programmable Chat: Invalid user channels limit format", "52107": "Invalid custom key for GCM/FCM", "91104": "Event type not found", "52072": "Client mqtt connection not created or closed", "13223": "Dial: Invalid phone number format", "22121": "Unable to Transfer Hosted Number", "60220": "Messages to China require use case vetting", "51131": "Twilsock: Authentication failed", "21655": "The ContentSid is Invalid", "50331": "Programmable Chat: Channel webhook trigger not provided", "50329": "Programmable Chat: Channel webhook url not provided", "53200": "Participant identity is invalid", "52111": "GCM/FCM unknown error", "21481": "Invalid PageToken", "80902": "No Active Session", "50441": "Failed to add a proxy address to a participant.", "33122": "Rate Plan Is Not Allowed", "21420": "ApplicationSid is not accessible", "22211": "Cannot create a Supporting Document with no FriendlyName", "52307": "No users with provided segments", "11237": "Certificate Invalid - Could not find path to certificate", "21247": "Trunk Dependencies", "61003": "Add-ons: Requirements to invoke AddOns have not been met", "90022": "One of 'TemplateArgs' dictionary value is too long", "54206": "Invalid Map Item data", "31207": "JWT token expiration too long.", "14108": "From phone number not SMS capable", "60511": "SNA Downstream Error", "50391": "Conflicting conversation modification", "50106": "Programmable Chat: Channel creator role not found", "32304": "Interconnect: Connection (TNX) SID is not Active", "60201": "Selected template translation is not approved", "20002": "Invalid FriendlyName", "60618": "Malformed request", "82007": "Unsupported Runtime", "53630": "Empty track list for composition", "80406": "Phone Number Did Invalid", "13218": "Dial: Invalid sequential value", "50368": "Conversation webhook type not provided", "63007": "Twilio could not find a Channel with the specified From address", "53107": "MaxParticipants is out of range", "60307": "Cannot resend push notifications to 'none' notification platform", "64008": "Pay: Payment Gateway rejected charge creation.", "21618": "The message body cannot be sent", "50214": "User conversation limit exceeded", "13238": "Dial->Conference: Invalid Verb used in waitUrl, holdUrl, or announceUrl TwiML", "53633": "Composition is too large", "61007": "Add-ons: Response body too large", "30104": "Shortened link not found. Click redirected to fallback Url", "83401": "The device was not attached to a cellular network", "22202": "No regulation sid or phone number country and type was provided", "53122": "The recording operation requested is not supported for the Room type", "19034": "Invalid country code", "64007": "Pay: Connector does not support creating charge.", "60601": "Authorization required for Canada lookups", "45359": "Failed to close Channel. Invalid status parameter.", "45009": "Configuration Error", "13239": "Dial->Conference: Invalid Trim Value", "80901": "Message Matched Stop Word", "11770": "Empty response body", "60610": "Phone number outside of coverage", "31600": "Busy Everywhere", "81008": "Failed to connect to outgoing Call", "48001": "Callback URL is not set", "33103": "Paging information invalid", "11300": "Invalid template URL", "80307": "Record to be updated was not found in database.", "21241": "Credential List Dependencies Violation", "52000": "Internal notification error", "20403": "403 Forbidden", "14219": "TaskRouter Dial Queue not supported in this realm", "54200": "Map not found", "19050": "Internal Server Error", "14105": "Invalid statusCallback attribute", "50512": "Message media size is too large", "31480": "Temporarily Unavailable", "30020": "Internal Failure with Message Scheduling", "80409": "Session Sid Invalid", "19025": "Channel validation error", "404": "Not Found", "62014": "Connection not ready", "90101": "Unique Name Already Exists", "13110": "Annotate: Annotate must contain one valid nested element", "80505": "Flex Configuration Error", "11200": "HTTP retrieval failure", "51111": "Twilsock: Service instance limit reached", "21224": "Invalid SipAuthPassword. Illegal chars", "52306": "Cannot delete User resource with Bindings", "32203": "SIP: Call blocked by Twilio", "60330": "Failed to invoke the webhook", "13810": "Reject: Invalid cause", "52136": "Missing payload for APNs delivery", "50326": "Programmable Chat: Invalid channel webhook trigger", "50405": "Programmable Chat: Invalid last consumption timestamp format", "14203": "Enqueue: Invalid Enqueue action url", "53625": "Access denied to external S3 bucket configured in composition settings", "31487": "Request Terminated", "60006": "Invalid Phone Number", "22115": "Invalid Unique Name", "35121": "OptimizeEndAt can only be used when ScheduleType is 'optimize'", "21479": "Unable to update Status for subaccount, subaccount has been closed.", "32015": "Call is terminated due to exceeding maximum call duration", "30010": "Message price exceeds max price", "21610": "Attempt to send to unsubscribed recipient", "21451": "Invalid area code", "53614": "Public key credentials for media tracks encryption could not be loaded", "50006": "Programmable Chat: Invalid Account SID", "50209": "Programmable Chat: Invalid binding type", "90001": "Message SID is invalid", "90011": "MessageSid is invalid", "62010": "No authentication was provided.", "62002": "Exchange not found", "32212": "SIP: Registration Authentication problem", "52051": "Internal error when sending notification via client connection", "45102": "Collision On Configuration Change", "52174": "Unexpected error response received for Webhook Credentials request", "21480": "Reached maximum number of subaccounts", "60520": "SNA URL Failed", "81013": "Failed to invoke Understand API", "31903": "Stream - WebSocket - Connection Broken Pipe", "13322": "Gather->Say: Invalid loop value", "19047": "Field definition name cannot be empty", "45600": "Flex UI error", "32505": "Voice Conversation: Invalid data inside existing conversation.", "13254": "Dial->Sip: SIP URI DNS does not resolve or resolves to an non-public IP address", "21717": "Brand Registration SID for US A2P Campaign Use Case is Not Registered or Not Valid", "11251": "Fatal protocol violation", "54302": "Invalid unique name", "70103": "Unsupported Public Key Exponent", "90034": "'BroadcastStatusCallbackUrl' is too long", "50306": "Programmable Chat: Unique name should not match channel SID pattern", "53611": "Invalid AWS credentials to access external S3 bucket in recording settings", "14234": "Dial->Conference: Unable to create task", "91103": "Event type list is empty", "31500": "Internal Server Error", "22104": "Invalid Email Format", "45352": "Failed to create an outbound Channel.", "50508": "Programmable Chat: Media already sent with another message", "22106": "Invalid Method", "21212": "Invalid From Number (caller ID)", "83400": "IP Commands error", "57001": "'Secret id' is empty", "20161": "Programmable Chat: Parameters are not specified for update request", "81018": "Template evaluation error in Studio widget", "13210": "Dial: Invalid method value", "50400": "Programmable Chat: User not member of channel", "60710": "Phone number CPS not found", "11201": "TCP connection timed out", "80207": " No unreserved numbers in proxy pool.", "20413": "Request Entity Too Large", "92002": "The 'variables' parameter exceeds the allowed limit", "81021": "Flow revision must be an integer or enum(LatestPublished, LatestRevision)", "90004": "Message Truncated", "13511": "Say: Invalid voice value", "14237": "Dial->Conference: Invalid PostWorkActivitySid", "54208": "Map Item already exists", "50341": "Invalid messaging service SID", "32105": "SIP: Invalid contact header", "91001": "Sink could not be found", "50407": "Invalid messaging binding address", "50433": "Participant already exists", "53402": "Client is unable to apply a remote media description", "12102": "The root element must be Response", "31400": "Bad Request", "51001": "Client Connection: Connections resource limit exceeded", "45745": "Invalid or missing parameters in the create conversation request.", "60300": "Invalid Param", "53216": "Participant session length exceeded", "52302": "Too many recipients", "45006": "Resource Not Found", "90100": "Invalid Autopilot Actions JSON", "22221": "Emergency address is not registered", "90029": "Broadcast 'CorrelationId' is empty", "60406": "Initialization Error", "53101": "Room name is too long", "90031": "Broadcast 'Recipients' list is empty", "31404": "Not Found", "19040": "Custom Field provided is not defined", "45764": "Unable to validate address configuration. Auto create webhook URL missing. ", "62004": "Direct connect not found.", "45201": "Resource Not Found", "63019": "Media failed to download", "60608": "Lookup provider error", "64015": "Pay: `` verb is missing a needed Parameter", "54510": "Query expression contains an array with too many items", "40111": "TaskRouter->Call", "32111": "SIP: Invalid header name", "31902": "Stream - WebSocket - Connection Refused", "53108": "RoomType is not valid", "32602": "Virtual Agent: Invalid Connector", "30026": "US A2P 10DLC - 70% T-Mobile Daily Message Limit Consumed", "30115": "Date format is incorrect", "35118": "MessagingServiceSid is required to schedule a message", "14241": "start_date passed to TaskRouter statistics is older than 30 days.", "90018": "'Template' field is too long", "62026": "Interconnect: Missing MPLS carrier SID", "21631": "Phone Number Requires an Address", "94001": "Transcriptions: Invalid transcribe value", "21615": "Phone Number Requires a Local Address", "13321": "Gather->Say: Invalid voice value", "21652": "Maximum subject length is 40 characters", "40144": "TaskRouter->Conference", "94201": "Transcriptions Settings: encryptionKeySid invalid or not found", "80203": "No Available Proxy For Country", "60329": "Verify SNA does not work with `psd2_enabled`", "54050": "Service Instance not found", "40100": "TaskRouter->Reject", "52138": "APNs payload too large", "50200": "Programmable Chat: User not found", "32100": "SIP: Trial accounts can only call verified caller IDs", "30008": "Unknown error", "13253": "Dial: Header is too long", "31102": "Authorization token missing in request.", "19004": "Invalid or missing Contact input", "19005": "Contact validation error", "80201": "No Available Voice Proxy", "90019": "'TemplateArgs' dictionary size is too large", "60533": "SNA Carrier Header Error", "400": "Bad Request", "30448": "Toll-Free phone number verification rejection - Age Gate", "13520": "Say: Invalid text", "48024": "Contact conversation limit exceeded", "45210": "Flex Flow creation failed", "60403": "Storage Error", "45402": "RTA feed callback response time exceeded the threshold", "31941": "Stream - Invalid Track configuration", "54151": "List Item not found", "21609": "Invalid 'StatusCallback'", "13338": "Gather: Invalid actionOnEmptyResult value", "52170": "Too many Webhook Credential requests", "64001": "Pay: Configuration Error", "22101": "Invalid Hosted Number Order SIDs", "51121": "Twilsock: Token expiration time exceeds maximum", "32401": "BYOC Trunk routing failure - failover to Twilio default routing.", "63021": "Channel invalid content error", "21624": "Invalid validity period value", "30449": "Toll Free verification rejection - Sample message URL issues in sample message", "53613": "AWS credentials to access external S3 bucket could not be loaded", "11310": "Invalid template token", "40149": "Failed to issue Conference instruction due to missing \u2018conference_sid\u2019", "83004": "Super SIM update operation failed due to Internal Error", "45004": "Validation Error", "54150": "List not found", "22201": "No regulation sid found for the given number group", "22100": "Reached Maximum Verification Attempts", "60531": "SNA Carrier Not Detected", "60008": "Unsupported Carrier", "50402": "Programmable Chat: Member not found", "31205": "JWT token expired.", "45372": "Failed to add Participant. Internal error.", "50432": "Participant not found", "80613": "Downstream Request Rejected", "62023": "Missing exchange", "53400": "Client is unable to create or apply a local media description", "45211": "Provided identity is reserved by system", "40131": "TaskRouter->Dequeue", "60722": "Business status does not allow dismissal", "83604": "The requested query period exceeds the maximum allowed period for the requested Granularity", "94300": "Transcriptions Configurations: Invalid callback configuration", "48010": "Custom Routing Callback failed to execute successfully", "51112": "Twilsock: Product usage disabled", "45353": "A duplicate create Channel request was dropped.", "50367": "Invalid conversation webhook flow SID", "80910": "Message To Voice Only Session Rejected", "94301": "Transcriptions Configurations: UniqueName is required", "31003": "Connection timeout", "21234": "Invalid Machine Detection configuration value", "62018": "Invalid IP route", "54007": "Access forbidden for identity", "20005": "Account not active", "53125": "The track kind is not supported by the Room", "50055": "Programmable Chat: Invalid webhook method", "48004": "Callback returned an error", "32110": "SIP: URI is formatted incorrectly", "45305": " No answer from Participant", "83006": "Super SIM\u2019s Target Fleet not found", "40141": "TaskRouter->Conference", "53111": "StatusCallback is invalid", "31105": "Invalid client name", "50061": "Programmable Chat: Invalid channel members limit format", "32504": "Voice Conversation: Incomplete Conversation.", "51120": "Twilsock: Token is not valid yet", "80305": "Not Found Unmanaged Identifier Sid", "50004": "Programmable Chat: Unique Name too long", "50610": "Address configuration deleted", "14231": "Dial->Conference: Provided Attributes was not valid JSON ", "55555": "Invalid Instruction passed to TaskRouter", "33120": "SIM connectivity reset in progress", "50305": "Programmable Chat: Channel SID not provided", "21230": "Maximum Domains Reached", "21262": "No AMD status callback URL provided", "62000": "Failed to write to the database.", "90038": "'BroadcastStatusCallbackUrl' is invalid", "21214": "'To' phone number cannot be reached", "52141": "The provided APNs device token has been unregistered", "53607": "Internal failure when updating the recording resource", "53003": "Client received an invalid signaling message", "63034": "Media exceeds size limit", "32700": "Voice User-Defined Message: Internal Twilio Error", "81022": "Flow definition validation failed", "51007": "Client Connection: Token authentication is rejected", "80603": "Non Unique Session Name", "57014": "'Event' data in payload is absent", "90026": "Template body could not be parsed", "60402": "Mapper Error", "63018": "Rate limit exceeded for Channel", "32002": "SIP: Dial failure - Twilio SIP Domain not found", "13224": "Dial: Twilio does not support calling this number or the number is invalid", "35119": "SendAt can only be used when ScheduleType is 'fixed'", "68007": "Authentication Token Error", "22103": "Unsupported Iso Country", "14206": "Enqueue: Invalid waitUrlMethod value", "40153": "Absolute Paging used when iterating TaskRouter resources", "94604": "Account Sid on Legal Hold.", "91201": "Bad Request", "21300": "Invalid BYOC trunk SID", "92001": "'Types' Parameter Required", "30001": "Queue overflow", "30120": " Domain certificate and private key are not uploaded", "31203": "No valid account.", "11241": "HTTP connection edge location is not supported", "50322": "Programmable Chat: Too many channel webhook triggers", "50334": "Channel deletion operation is in progress", "30113": "Specified date is too old", "14232": "Dial->Conference: Invalid Priority", "13237": "Dial->Conference: Invalid Conference Name", "60225": "Translation already exists for the provided template", "31950": "Stream - Protocol - Malformed Message", "21215": "Geo Permission configuration is not permitting call", "13621": "Invalid 'recordingStatusCallbackEvent'", "80405": "Participant Sid Invalid", "21474": "API User must be the parent account to transfer phone numbers.", "13250": "Dial: Too many URIs passed", "13314": "Gather: Invalid numDigits value", "52161": "Empty Credentials", "80909": "Inbound Contact Rejected", "83600": " An invalid parameter value was passed to the API", "32506": "Voice Conversation: Failed to get worker assigned to a newly created Conversation.", "30023": "US A2P 10DLC - Daily Message Cap Reached", "50406": "Programmable Chat: Invalid last consumed message index format", "40145": "TaskRouter->Conference", "50069": "Programmable Chat: Service instance with provided unique name already exists", "62013": "Unable to identify account owner of connection.", "51119": "Twilsock: Token expired", "60540": "SNA Carrier Identified Invalid Phone Number", "63012": "Channel provider returned an internal service error", "53406": "The data channel used by the Data Track had a problem", "93105": "Consent has already been provided for this account and vendor", "80610": "Unauthorized Operation", "31603": "Decline", "32012": "SIP: Master account pooled Trunking CPS limit exceeded", "21216": "API: Call blocked by Twilio blocklist", "60703": "Invalid phone numbers format", "52301": "Resulted destination list for requested parameters is empty", "21213": "Caller phone number is required", "90036": "Broadcast recipient's 'body' is too long", "50050": "Programmable Chat: Service Instance not found", "57008": "'EventType' format must be String", "13211": "Dial: Invalid ifMachine value", "31302": "Unsupported Cancel Message Error", "51005": "Client Connection: Command or keepalive acknowledgement not received", "64021": "Pay: Invalid Operation", "60700": "Something went wrong. Try again later", "50349": "Conflicting channel modification", "53667": "AWS credentials to access external S3 bucket could not be loaded", "13803": "SMS verb not supported in this realm", "21719": "Incompatible Messaging Service/A2P Use Cases", "22109": "Invalid Address SID", "21724": "Brand update count exceeded", "63027": "Template does not exist for a language and locale", "30132": "Certificate cannot be validated. ", "12400": "Internal Failure", "33104": "Configuration incomplete", "53004": "Client sent an invalid signaling message", "32114": "SIP: Unsupported parameter value", "21450": "Phone number already validated on your account", "30410": "Provider Timeout Error", "21454": "Invalid CallDelay", "50503": "Programmable Chat: Message body not provided", "40136": "TaskRouter->Conference", "21626": "Invalid 'StatusCallbackEvent'", "32710": "Voice User-Defined Message: Subscription Callback Internal Error", "63005": "Channel did not accept given content. Please see Channel specific error message for more information", "63013": "Channel policy violation", "32011": "Error communicating with your SIP communications infrastructure", "13410": "Play: Invalid loop value", "21401": "Invalid Phone Number", "70153": "Public Key Specified Does Not Exist", "33203": "Messaging not allowed", "20160": "Invalid Token", "60226": "Messages sent to china require friendly_name", "21645": "Supporting Document cannot be deleted due to active Regulatory Bundle assignment", "53623": "AWS credentials to access external S3 bucket could not be loaded", "91002": "Incorrect values for pagination", "50109": "Conversation role not found", "70152": "Request Contains Invalid Flags", "60222": "SendGrid The from address does not match a verified Sender Identity", "80202": "No Available Message Proxy", "45741": "Failed to create webchat conversation. Account not authorized ", "30017": "Carrier network congestion", "21651": "Document does not satisfy regulatory requirement", "60217": "Invalid Service configuration", "64013": "Pay: Connector does not support supplied paymentMethod attribute.", "20503": "Service unavailable", "30028": "Invalid API version", "40132": "TaskRouter->Dequeue", "21713": "Messaging Service Use Case is Invalid", "62035": "Interconnect: No bandwidth was specified in the request", "94000": "Transcriptions: request to transcribe audio error", "68005": "Key Storage Error", "13232": "Dial->Conference: Invalid startConferenceOnEnter value", "21901": "DltTemplateId is invalid", "53302": "Track name is too long", "30030": "Invalid AddressRetention", "50065": "Programmable Chat: Invalid webhook retry count", "50443": "Failed to add a projected address to a participant.", "21603": "A 'From' or 'MessagingServiceSid' parameter is required to send a message", "57010": "'PartnerName' is absent", "13619": "Record: Transcription feature not available for this type of recording.", "19013": "At least one of the following fields is required for a contact: first_name, middle_name, last_name, legal_name, preferred_name, unique_customer_provided_id or channel", "32201": "SIP: Source IP address not in ACL", "63030": "Unsupported parameter for type of channels message", "53118": "Room Completed Error", "10004": "Call concurrency limit exceeded", "54008": "Invalid JSON", "31005": "Connection error", "40112": "TaskRouter->Call", "32604": "Virtual Agent: Internal Error", "32013": "SIP: Master account SIP Interface CPS limit exceeded", "60207": "Max rate limits per service reached ", "50342": "Messaging service does not belong to account", "14107": "SMS send rate limit exceeded", "53660": "Status Callback response timed out", "60725": "Brand status does not allow to have branded channels", "63002": "Channel could not find the From address", "60605": "Verification delivery attempt blocked", "19037": "When updating a location at least one field should be updated", "45202": "Resource Already Exists", "31951": "Stream - Protocol - Invalid Message", "62022": "Missing account SID", "13213": "Dial: Invalid hangupOnStar value", "11205": "HTTP connection failure", "30109": "Callback URL is invalid", "51102": "Twilsock: Service instance SID not specified", "62016": "Connection not active", "16104": "Voice Recording: Unavailable due to encryption failure", "21656": "The ContentVariables Parameter is invalid", "50076": "Webhook failed to execute successfully due to timeout", "45312": "Remove Participant Request Failed", "57012": "Signature invalid", "31204": "Invalid JWT token.", "52142": "The provided APNs device token is not correct", "32022": "ACK not received from your SIP endpoint", "50390": "Unique name should not match conversation sid pattern", "50376": "TimeToClosed should be greater or equal to 10 minutes", "45007": "Resource Conflict Error", "53666": "Invalid public key for media tracks encryption in composition settings", "22199": "Configuration Retrieval Error", "30102": "Domain's certificate has expired", "53201": "Participant identity is too long", "63015": "Channel Sandbox can only send messages to phone numbers that have joined the Sandbox", "21649": "Phone Number Requires a Bundle", "92006": "The Content Sid is Invalid", "63040": "Template submission failure", "54209": "Invalid Map Item key", "64012": "Pay: Payment Gateway rejected the card.", "54458": "Invalid List Item index", "31301": "Registration error", "60204": "Service does not support this feature", "60715": "Error reading logo file", "51129": "Twilsock: Too many messages per account", "14223": "Enqueue: Unable to cleanup task", "54205": "Map Item revision mismatch", "80103": "Participant Already In Session", "410": "Unknown Error Code", "94602": "Invalid FromDate", "50366": "Invalid conversation webhook trigger", "32210": "SIP: Register not supported", "19052": "Invalid page size for custom field definition", "31960": "Stream - Quota exceeded", "53401": "Server is unable to create or apply a local media description", "63032": "We cannot send this message to this user because of a WhatsApp limitation. ", "20003": "Permission Denied", "82008": "Headers or cookies too large", "48000": "Invalid request payload", "80701": "Parameter Validation Failed", "31106": "Invalid data", "45313": "Transfer Failed", "21217": "Phone number does not appear to be valid", "54056": "Account cannot access requested Service Instance", "53124": "The AudioOnly flag is not supported for the Room type", "60227": "The selected channel for template is not supported", "21621": "The 'From' number has not been enabled for MMS", "14300": "Start: Invalid nested noun value", "21245": "Trunk Validation Error", "40122": "TaskRouter->Direct", "64020": "Pay: Invalid Parameter Value", "50392": "PreWebhookTimeout should be greater than 0ms", "50500": "Programmable Chat: Message not found", "32703": "Voice User-Defined Message: Content body exceeded max length", "30443": "Toll Free verification rejection - Disallowed Content", "60603": "SendGrid maximum credits exceeded", "13249": "Dial: Invalid username or password attribute", "82003": "Deployment Installation Failure", "13215": "Dial: Invalid nested element", "52303": "Concurrent User update", "21202": "Called number is a premium number", "456001": "Approaching Flex Plugin creation limit", "22116": "Invalid Friendly Name", "53407": "Media connection failed due to DTLS handshake failure", "32214": "SIP: Invalid ", "456002": "Approaching Flex Plugin Version creation limit", "45401": "RTA feed callback returned not successful response code", "32221": "Dialing SIP Endpoint failure - No devices registered in specified edge", "45761": "Failed to validate address configuration. Auto create not enabled.", "16109": "Voice Recording: Cannot fetch .mp3 encrypted recording", "50002": "Programmable Chat: Resource is being deleted", "21225": "SipAuthPassword is required when providing SipAuthUsername", "21455": "Invalid PlayUrl", "30005": "Unknown destination handset", "94101": "Transcriptions: status callback response timed out", "50308": "Programmable Chat: Invalid Date Created parameter", "31900": "Stream - Unknown Error", "13235": "Dial->Conference: Invalid beep value", "51128": "Twilsock: Too many messages per connection", "32400": "BYOC Trunk routing failure - failover routing disabled.", "13236": "Dial->Conference: Invalid Conference Sid", "16107": "Voice Recording: Encrypted with alternate public key", "53631": "Failed to enqueue a room composition from a configured composition hook", "21405": "Cannot set VoiceFallbackUrl without setting Url", "32010": "SIP: No valid Origination URIs configured", "30110": "Domain is blocked", "31403": "Forbidden", "22110": "Phone Number Not Hostable", "32206": "SIP: Invalid From number (caller ID)", "14109": "TwiML Reply message limit exceeded", "70002": "Bad request", "48002": "Callback URL is invalid", "45765": "Address configuration data not found", "80616": "Unsupported Identifier Type For Session Mode", "81001": "The Widget has exceeded max steps in a loop", "21260": "Maximum number of actions per rule reached", "68004": "Input Error", "32223": "There is no username in the SIP URI when calling a SIP registered endpoint", "13513": "Say: Invalid rate value", "32600": "Virtual Agent: Configuration Error", "33121": "Invalid Parameter Combination", "48026": "Outgoing conversation: Invalid proxy address", "50103": "Programmable Chat: Role SID not provided", "31931": "Stream - Media - Media Discarded", "21223": "Invalid SipAuthPassword. Must be fewer than 256 chars", "35114": "Scheduling does not support this timestamp", "45303": "Participant was busy", "60717": "Error uploading logo to the storage", "68003": "Storage Error", "50504": "Programmable Chat: Message body parameter is too long", "21900": "DltPEId is invalid", "45304": "Internal timeout error", "63024": "Invalid message recipient", "15003": "Call Progress: Warning Response to Callback URL", "40113": "TaskRouter->Call", "19003": "Contact with the unique_customer_provided_id provided already exists", "15000": "Call Progress: Internal Twilio Error", "60708": "Phone record number not found", "45205": "Requested Flex Flow is not found", "45363": "Failed to remove Participant. Downstream error.", "40133": "TaskRouter->Dequeue", "83601": "Request StartTime and/or EndTime must be aligned to UTC day boundaries", "52148": "Expired APNs provider token used", "21240": "Credential List Validation Error", "31924": "Stream - Websocket - Protocol Error", "16021": "Failed to join conference due to account concurrency limit exceeded", "31100": "Malformed request", "21206": "Invalid SendDigits", "21261": "Maximum number of conditions per rule reached", "70053": "Public Key Client Validation Not Enabled For Account", "80205": "No Proxies For Service", "80620": "Chat Configured Proxy Identifier Not Found", "52212": "Missing Alexa skill ID", "21704": "The Messaging Service contains no phone numbers", "50307": "Programmable Chat: Channel with provided unique name already exists", "21646": "Supporting Document is not eligible for deletion", "81000": "The Execution has exceeded max steps allowed for a flow", "53403": "Server is unable to apply a remote media description", "50300": "Programmable Chat: Channel not found", "21721": "Cannot import Campaign Verify token due to incompatible A2P brand", "60617": "Not enough arguments", "34005": "Programmable Fax is no longer available", "45354": "Cannot create a Channel for a closed Conversation.", "60206": "'Amount' & 'Payee' params are required", "60219": "SendGrid Template does not contain required placeholders", "50409": "Participant address equals proxy address", "52003": "Invalid Credential Type", "21228": "Invalid SIP Header. Illegal chars in header name", "50325": "Programmable Chat: Invalid channel webhook filter", "81009": "Timed out enqueueing Call", "31201": "Twilio Client: Error occurred while accessing microphone", "21232": "Invalid Domain", "11206": "HTTP protocol violation", "16000": "Whisper Not Available on Twilio Conference", "91202": "Not Found", "51103": "Twilsock: Token doesn't contain required grants section", "80908": "Callback Error", "13219": "Dial: Invalid answerOnBridge value", "81010": "There was an internal error while processing a Function", "80601": "Phone Number Not Available", "54010": "No parameters specified", "19043": "Field definition name already exists", "32115": "X-Branded-CallReason header contains an invalid value.", "14207": " Enqueue: The targeted queue reached max queue size", "40148": "Failed to issue Supervise instruction due to missing \u2018from\u2019 property", "21258": "Invalid SIP Manipulation Policy", "13710": "Redirect: Invalid method value", "23001": "Message Redaction Incompatible Configuration: Long code STOP filtering", "14104": "Invalid Method attribute", "21634": "SIP Trunk is in use for emergency calling", "48003": "Callback returned an invalid response", "50404": "Programmable Chat: Member already exists", "80402": "Identifier Proxy Pair Invalid", "90000": "Uncaught Flex JavaScript Exception", "90020": "One of 'TemplateArgs' dictionary key is blank", "52168": "Webhook Credentials request timed out", "21221": "Invalid SipAuthUsername. Must be fewer than 256 chars", "31101": "Missing parameter array in request.", "20001": "Unknown parameters", "80801": "Invalid attempt to Re-Open a Session", "90028": "Broadcast 'IdempotencyToken' is too long", "13512": "Gather element has an invalid \"language\" attribute value", "30014": "'To' attributes are Invalid", "21100": "Accounts Resource", "60409": "Custom message did not match any template", "50323": "Programmable Chat: Invalid channel webhook sid", "21476": "Unable to update Status for subaccount, parent account is suspended.", "50063": "Programmable Chat: Actions per second limit exceeded", "20426": "Upgrade Required", "53105": "Room contains too many Participants", "90033": "Broadcast recipient's 'to' is too long", "22216": "Missing Supporting Document", "31007": "Twilio Client: Client version not supported", "45008": "Unprocessable Request", "48023": "Frontline user conversation limit exceeded", "20009": "Cannot delete this resource before it is complete", "60331": "Locale requested is not supported by Verify Text-To-Speech conversion", "22123": "Unable to Initiate Verification Call", "94302": "Transcriptions Configurations: UniqueName is invalid", "13613": "Record: Invalid finishOnKey value", "11210": "HTTP bad host name", "21219": "'To' phone number not verified", "21404": "Inbound Phone number not available to trial account", "40154": "Invalid Known Worker information", "21622": "MMS has not been enabled for your account", "61002": "Add-ons: Provider could not complete request", "80506": "Service Creation is restricted for new customers", "52147": "Too many APNs provider token updates", "20008": "Test Credentials", "51115": "Twilsock: Invalid access token subject", "32222": "TLS version not allowed", "53303": "Track name contains invalid characters", "31503": "Service Unavailable", "80404": "Participant Identifier Invalid", "50360": "Conversation webhook not found", "50444": "Failed to add an identity to a participant.", "61006": "Add-ons: Add-ons unavailable for GET callbacks", "13620": "Record: Transcription not available for this recording", "20010": "Action disabled for account", "45212": "Flex Flow creation failed", "63033": "Recipient blocked to receive message", "60405": "Key Storage Error", "52002": "Invalid Credential Sid", "21208": "Invalid Timeout", "22228": "From Bundle does not have latest Regulation requirements that matches destination Bundle", "31001": "Application not found.", "54454": "Sync: Invalid 'PageSize' query parameter", "60322": "Challenge already responded", "21200": "Calls Resource", "60314": "Factors binding format is invalid", "90023": "One of 'TemplateArgs' dictionary value is null", "52139": "APN service shutdown", "21629": "Address Validation Error - Check Suggested Address", "90035": "Broadcast 'MessageStatusCallbackUrl' is too long", "80609": "Too Many Added Participants", "13337": "Gather: callback must be over HTTPS when using gather with PCI compliance", "23003": "Message Redaction Incompatible Configuration: Sticky Sender", "53610": "Invalid URL for external S3 bucket in recording settings", "51124": "Twilsock: Too many connections", "50302": "Programmable Chat: Unknown channel command", "13258": "Dial->Sim not supported in this realm", "60302": "FactorType already exists", "62052": "Interconnect: This account is not a subaccount of the Interconnect Connection owner's account.", "70005": "Failure Threshold Exceeded", "60701": "Invalid request", "53602": "AWS encryption key for recording upload is invalid", "45368": "Failed to delete Channel. Not found.", "32501": "Voice Conversation: TwiML attributes validation error.", "60301": "Entity already exists", "14205": "Enqueue: Queue name too long", "50102": "Programmable Chat: Deployment role not found", "45310": "Participant Not Found", "60305": "Access Token parameters are invalid", "63010": "Twilio's platform encountered an internal error processing this message", "60613": "Lookup Provider Degradation", "50411": "Participant address is empty", "13256": "Invalid recordingStatusCallback URL", "13214": "Dial: Invalid callerId value", "80408": "Service Sid Invalid", "50372": "Conversation webhook URL is too long", "21254": "Max Connection Policy Entries Reached", "13243": "Dial->SIP: Invalid SIP URI", "21238": "Address Validation Error", "53119": "The concurrent Rooms quota was exceeded", "21728": "Campaign registration failed due to length validation failures", "16111": "Voice Recording: Upload file to external AWS S3 bucket failed (Invalid Configuration)", "50430": "Participant is not a member of conversation", "53604": "Failed to upload the recording to S3", "80608": "Session Status Invalid", "45001": "General Service Error", "13320": "Gather: Invalid nested verb", "30015": "Non-supported channel type is used", "60203": "Max send attempts reached.", "33118": "Number of Commands exceeded", "50353": "Conversation with provided unique name already exists", "21251": "Trunking CPS change not allowed", "50000": "Programmable Chat: FriendlyName not provided", "16001": "Conference is not bridged", "21458": "PhoneNumber Provisioning Type Mismatch", "14201": "Enqueue: Invalid method value", "20152": "Invalid Header", "22107": "Unable to Update Authorization Document", "63017": "Rate limit exceeded", "20106": "Invalid Access Token grants", "70101": "Unsupported Public Key Algorithm", "50601": "Programmable Chat: Invite not found", "22300": "This account is restricted from provisioning new long code phone numbers", "21243": "Credential Validation Error", "51123": "Twilsock: Upstream not resolved", "20023": "Phone number is not correct: it cannot be null or have non-decimal symbols", "13334": "Gather: Invalid model value", "70151": "Maximum Number Of API Keys Exceeded", "92003": "'language' Parameter Required", "51002": "Client Connection: Request rate limit exceeded", "22229": "Supporting Document Bundle Assignment cannot be removed", "13225": "Dial: Call blocked by Twilio block list", "22001": "Call timed out", "80102": "Participant Already In Interaction", "83009": "Unable to update your Super SIM\u2019s Fleet while it is in status scheduled", "31942": "Stream - Invalid connector configuration", "70003": "Outdated Entity", "32204": "SIP: 'From' phone number not verified", "31481": "Call/Transaction Does Not Exist", "32502": "Voice Conversation: Callback event internal error.", "90024": "Template body has tag which is not provided in 'TemplateArgs'", "13255": "Dialing .sip.twilio.com addresses is not currently allowed", "53100": "Room name is invalid", "40139": "Failed to issue Conference Instruction due to invalid ActivitySid", "31006": "Audio device error", "21727": "Campaign registration failed due to missing parameter(s)", "62011": "Unauthorized", "45715": "Failed to create webchat participant. Invalid request parameters. ", "52101": "Invalid GCM Api Key or FCM Secret", "14215": "Dial->Queue: Invalid ReservationSid. Unable to dequeue", "63026": "Channel sender content flagged as spam", "14102": "Invalid \"From\" attribute", "53612": "Invalid public key for media tracks encryption in recording settings", "48033": "Outgoing conversation: Invalid contact identity", "50453": "Proxy Address of participant is not supported for this channel", "45306": "Meeting was canceled", "91100": "Subscription could not be created", "13699": "Record: Invalid trim value", "80615": "Account Sid on Legal Hold", "50439": "Account is not authorized to use the projected address", "53600": "S3 URL for recording upload is invalid", "12200": "Schema validation warning", "31921": "Stream - WebSocket - Close Error", "23006": "Message Redaction Incompatible Configuration: Inbound Webhook GET Requests", "83701": "Data Session Establishment Failed Due To Internal Error", "50510": "Invalid message media SID", "21714": "Messaging Service Number Pool size limit reached", "94501": "Transcriptions: Status invalid", "80907": "Open Interaction Not Found", "32018": "Twiml size exceeded maximum allowed value", "81015": "Failed to Create Task", "50347": "Parameters are missing for channel update request", "52173": "Unexpected Identifier used for Webhook Credentials request", "61009": "Add-ons: Could not fulfill request with available data", "60309": "Push notifications limit reached for a Challenge", "50210": "Programmable Chat: Invalid notification level", "35120": "OptimizeStartAt can only be used when ScheduleType is 'optimize'", "30004": "Message blocked", "53209": "Participant status is invalid", "64003": "Pay: Invalid charge amount.", "20006": "Access Denied", "50501": "Programmable Chat: Message SID not provided", "63037": "Channel Media Upload Error", "21715": "Phone Number Does Not Have Correct Messaging Service Capabilities", "60726": "Business status does not allow to have brands", "60724": "Brand status does not allow dismissal", "21647": "Regulatory Bundle is not eligible for deletion", "14110": "Invalid Verb for SMS Reply", "83704": "Attachment Rejected Due To SIM In New State", "40110": "TaskRouter->Call", "19049": "Custom field definition provided is not defined", "22219": "An Address is missing", "63039": "Warning! Facebook says your page is engaging in behavior that may be considered bothersome or abusive by users. To avoid messaging restrictions being placed on your Page, Facebook requires you to immediately decrease the rate at which you are sending messages outside the 24-hour window to this person.", "58002": "The MediaProcessor concurrency quota was exceeded", "50001": "Programmable Chat: Account SID not provided", "81020": "Unsupported Trigger Type", "80104": "Phone Number Already In Service", "11215": "HTTP too many redirects", "14210": "Dial->Queue: Invalid whisper method", "52106": "Notification too large for GCM/FCM", "53624": "Public key credentials for media tracks encryption could not be loaded", "21205": "Invalid URL", "52110": "GCM/FCM service unavailable", "50505": "Programmable Chat: Last Updated By parameter is too long", "19036": "Invalid page token", "40146": "Failed to issue Supervise Instruction due to invalid Reservation state", "81023": "Creating an Execution via REST API failed due to malformed contact parameters", "45350": "An unexpected error occurred.", "53121": "Approaching room or participant concurrency quota", "60001": "Downstream Authentication Failed", "21644": "End-User cannot be deleted due to an active assignment to a Bundle", "32302": "Interconnect: Connection (TNX) SID not found", "52201": "Too many Facebook messenger notification requests", "53606": "Internal failure when creating the recording resource", "70154": "Public Key Is Invalid", "50365": "Invalid conversation webhook filter", "14103": "Invalid Body", "32200": "SIP: Insufficient permissions", "13201": "Dial: Cannot Dial out from a Dial Call Segment", "30106": "Domain has not been set up for this account", "13311": "Gather: Invalid finishOnKey value", "11240": "HTTP connection edge location is invalid", "16027": "Participant to be whispered is on hold", "60214": "Call channel is not supported when using PSD2", "11220": "SSL/TLS Handshake Error", "93102": "There was an error with your AWS role", "21726": "Starter brand registrations and updates are temporarily disabled", "68001": "Network Error", "35115": "Scheduling does not support this timestamp", "21470": "Invalid AccountSid", "81011": "Failed to send Message", "19020": "Contact with the provided channel value already exists", "52134": "Invalid APNs device token", "30013": "TTL is too big", "30018": "Destination carrier requires sender ID pre-registration", "54419": "Number of subscriptions per connection is over the limit", "53665": "Invalid AWS credentials to access external S3 bucket in composition settings", "31484": "Address Incomplete", "51101": "Twilsock: Service instance not found", "50301": "Programmable Chat: Channel key not provided", "50385": "Conversations are disabled in this region", "53615": "Access denied to external S3 bucket configured in recording settings", "94603": "Ttl is out of range", "62220": "Provisioning failure - Requested bandwidth not available on the network device.", "51117": "Twilsock: Invalid access token signature", "21617": "The concatenated message body exceeds the 1600 character limit", "16112": "Voice Recording: Upload file to external AWS S3 bucket failed (Access Denied)", "54250": "Message Stream not found", "13216": "Invalid timeLimit value", "30101": "Domain is unverified", "90040": "Broadcast 'MediaUrls' list has too many items", "60600": "Unprovisioned or out of coverage", "30025": "US A2P 10DLC - 50% T-Mobile Daily Message Limit Consumed", "60210": "Max Buckets per Rate limit reached", "63014": "Channel message blocked by user action", "90021": "One of 'TemplateArgs' dictionary key is too long", "14218": "Dial->Queue: Could not update worker to provided activity", "80401": "Account Sid Invalid", "13325": "Gather->Play: Invalid Content-Type", "60711": "Business status does not allow updates", "45204": "Requested Flex Chat Channel is not found", "22226": "Cannot replace Items from Bundle to same Bundle"} \ No newline at end of file diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index 7f79cf40a..48388e61c 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -9,6 +9,7 @@ import ( "context" "crypto/hmac" "crypto/sha1" + _ "embed" "encoding/base64" "fmt" "net/http" @@ -41,6 +42,9 @@ const ( var ( maxMsgLength = 1600 twilioBaseURL = "https://api.twilio.com" + + //go:embed errors.json + errorCodes []byte ) // see https://www.twilio.com/docs/sms/accepted-mime-types#accepted-mime-types @@ -299,7 +303,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, err } } - clog.Error(courier.ErrorServiceSpecific("twilio", strconv.Itoa(int(errorCode)), "")) + clog.Error(twilioError(errorCode)) return status, nil } } @@ -441,3 +445,9 @@ func (h *handler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter _, err := fmt.Fprintf(w, ``, details) return err } + +func twilioError(code int64) *courier.ChannelError { + codeAsStr := strconv.Itoa(int(code)) + errMsg, _ := jsonparser.GetString(errorCodes, codeAsStr) + return courier.ErrorServiceSpecific("twilio", codeAsStr, errMsg) +} diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index 0ac6d8726..6b76cb4eb 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -350,7 +350,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStopEvent: true, ExpectedMsgStatus: "F", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "Attempt to send to unsubscribed recipient")}, SendPrep: setSendURL, }, { @@ -457,7 +457,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedStopEvent: true, ExpectedMsgStatus: "F", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "Attempt to send to unsubscribed recipient")}, SendPrep: setSendURL, }, { @@ -542,7 +542,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "F", ExpectedStopEvent: true, - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "Attempt to send to unsubscribed recipient")}, SendPrep: setSendURL, }, { @@ -627,7 +627,7 @@ var swSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "F", ExpectedStopEvent: true, - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "Attempt to send to unsubscribed recipient")}, SendPrep: setSendURL, }, { diff --git a/tools/twiml_errors.py b/tools/twiml_errors.py new file mode 100755 index 000000000..c4145d323 --- /dev/null +++ b/tools/twiml_errors.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python3 +import json +import requests + + +response = requests.get("https://www.twilio.com/docs/documents/76/twilio-error-codes.json") +codes = {str(e["code"]): e["message"] for e in response.json()} +with open("../handlers/twiml/errors.json", "w") as f: + f.write(json.dumps(codes)) From 2fd8e7e7ee4f4e469ef3ffff881b822590a39a9d Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 17 Nov 2022 15:04:26 -0500 Subject: [PATCH 270/294] Log error to channel log for Twilio DLRs --- handlers/nexmo/nexmo_test.go | 1 + handlers/test.go | 4 +++ handlers/twiml/twiml.go | 25 +++++++++------- handlers/twiml/twiml_test.go | 56 ++++++++++++++++++++++++++++++------ 4 files changed, 67 insertions(+), 19 deletions(-) diff --git a/handlers/nexmo/nexmo_test.go b/handlers/nexmo/nexmo_test.go index 443a8e6d4..445bca387 100644 --- a/handlers/nexmo/nexmo_test.go +++ b/handlers/nexmo/nexmo_test.go @@ -77,6 +77,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedBodyContains: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedExternalID: "external1", + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("vonage", "d6", "Anti-Spam Rejection")}, }, { Label: "Status accepted", diff --git a/handlers/test.go b/handlers/test.go index 6d83eb4ae..9af8e3f95 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -52,6 +52,7 @@ type ChannelHandleTestCase struct { ExpectedMsgID int64 ExpectedEvent courier.ChannelEventType ExpectedEventExtra map[string]interface{} + ExpectedErrors []*courier.ChannelError } // MockedRequest is a fake HTTP request @@ -222,6 +223,9 @@ func RunChannelTestCases(t *testing.T, channels []courier.Channel, handler couri // if we're expecting a message, status or event, check we have a log for it if tc.ExpectedMsgText != nil || tc.ExpectedMsgStatus != "" || tc.ExpectedEvent != "" { assert.Greater(t, len(mb.WrittenChannelLogs()), 0, "expected at least one channel log") + + clog := mb.WrittenChannelLogs()[0] + assert.Equal(t, tc.ExpectedErrors, clog.Errors(), "unexpected errors logged") } }) } diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index 48388e61c..b91b6009f 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -193,19 +193,21 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } errorCode, _ := strconv.ParseInt(form.ErrorCode, 10, 64) - if errorCode == errorStopped { - urn, err := h.parseURN(channel, form.To, "") - if err != nil { - return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) - } + if errorCode != 0 { + if errorCode == errorStopped { + urn, err := h.parseURN(channel, form.To, "") + if err != nil { + return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) + } - // create a stop channel event - channelEvent := h.Backend().NewChannelEvent(channel, courier.StopContact, urn, clog) - err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) - if err != nil { - return nil, err + // create a stop channel event + channelEvent := h.Backend().NewChannelEvent(channel, courier.StopContact, urn, clog) + err = h.Backend().WriteChannelEvent(ctx, channelEvent, clog) + if err != nil { + return nil, err + } } - + clog.Error(twilioError(errorCode)) } return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r) @@ -446,6 +448,7 @@ func (h *handler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter return err } +// https://www.twilio.com/docs/api/errors func twilioError(code int64) *courier.ChannelError { codeAsStr := strconv.Itoa(int(code)) errMsg, _ := jsonparser.GetString(errorCodes, codeAsStr) diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index 6b76cb4eb..1137c2c63 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -98,8 +98,18 @@ var testCases = []ChannelHandleTestCase{ {Label: "Receive Base64", URL: receiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status Stop contact", URL: statusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", - PrepRequest: addValidSignature}, + { + Label: "Status Stop contact", + URL: statusURL, + Data: statusStop, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, + ExpectedEvent: "stop_contact", + ExpectedURN: "tel:+12028831111", + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "Attempt to send to unsubscribed recipient")}, + PrepRequest: addValidSignature, + }, {Label: "Status No Params", URL: statusURL, Data: " ", ExpectedRespStatus: 200, ExpectedBodyContains: "no msg status, ignoring", PrepRequest: addValidSignature}, {Label: "Status Invalid Status", URL: statusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedBodyContains: "unknown status 'huh'", @@ -135,8 +145,18 @@ var tmsTestCases = []ChannelHandleTestCase{ {Label: "Receive Base64", URL: tmsReceiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status Stop contact", URL: tmsStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", - PrepRequest: addValidSignature}, + { + Label: "Status Stop contact", + URL: tmsStatusURL, + Data: statusStop, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, + ExpectedEvent: "stop_contact", + ExpectedURN: "tel:+12028831111", + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "Attempt to send to unsubscribed recipient")}, + PrepRequest: addValidSignature, + }, {Label: "Status TMS extra", URL: tmsStatusURL, Data: tmsStatusExtra, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"S"`, ExpectedMsgStatus: courier.MsgSent, ExpectedExternalID: "SM0b6e2697aae04182a9f5b5c7a8994c7f", PrepRequest: addValidSignature}, {Label: "Status No Params", URL: tmsStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedBodyContains: "no msg status, ignoring", @@ -174,8 +194,18 @@ var twTestCases = []ChannelHandleTestCase{ {Label: "Receive Base64", URL: twReceiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", PrepRequest: addValidSignature}, - {Label: "Status Stop contact", URL: twStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", - PrepRequest: addValidSignature}, + { + Label: "Status Stop contact", + URL: twStatusURL, + Data: statusStop, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, + ExpectedEvent: "stop_contact", + ExpectedURN: "tel:+12028831111", + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "Attempt to send to unsubscribed recipient")}, + PrepRequest: addValidSignature, + }, {Label: "Status No Params", URL: twStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedBodyContains: "no msg status, ignoring", PrepRequest: addValidSignature}, {Label: "Status Invalid Status", URL: twStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedBodyContains: "unknown status 'huh'", @@ -198,8 +228,18 @@ var swTestCases = []ChannelHandleTestCase{ ExpectedMsgText: Sp("Msg"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b", ExpectedAttachments: []string{"cat.jpg", "dog.jpg"}}, {Label: "Receive Base64", URL: swReceiveURL, Data: receiveBase64, ExpectedRespStatus: 200, ExpectedBodyContains: "", ExpectedMsgText: Sp("Bannon Explains The World ...\n“The Camp of the Saints"), ExpectedURN: "tel:+14133881111", ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, - {Label: "Status Stop contact", URL: swStatusURL, Data: statusStop, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", - PrepRequest: addValidSignature}, + { + Label: "Status Stop contact", + URL: swStatusURL, + Data: statusStop, + ExpectedRespStatus: 200, + ExpectedBodyContains: `"status":"F"`, + ExpectedMsgStatus: courier.MsgFailed, + ExpectedEvent: "stop_contact", + ExpectedURN: "tel:+12028831111", + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "Attempt to send to unsubscribed recipient")}, + PrepRequest: addValidSignature, + }, {Label: "Status No Params", URL: swStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedBodyContains: "no msg status, ignoring"}, {Label: "Status Invalid Status", URL: swStatusURL, Data: statusInvalid, ExpectedRespStatus: 400, ExpectedBodyContains: "unknown status 'huh'"}, {Label: "Status Valid", URL: swStatusURL, Data: statusValid, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"D"`, ExpectedMsgStatus: courier.MsgDelivered, ExpectedExternalID: "SMe287d7109a5a925f182f0e07fe5b223b"}, From f7c4fbf4d445b50f6d0fb296758ba259f414409e Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 18 Nov 2022 12:13:44 -0500 Subject: [PATCH 271/294] Update to latest gocommon which provides dbutil.ToValidUTF8 --- backends/rapidpro/backend.go | 5 +--- go.mod | 2 +- go.sum | 4 ++-- handlers/clickatell/clickatell.go | 3 +-- handlers/highconnection/highconnection.go | 3 +-- utils/misc.go | 29 ----------------------- utils/misc_test.go | 12 ---------- 7 files changed, 6 insertions(+), 52 deletions(-) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 5b1ebc811..a2f511203 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -21,7 +21,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/batch" "github.com/nyaruka/courier/queue" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/analytics" "github.com/nyaruka/gocommon/dbutil" "github.com/nyaruka/gocommon/jsonx" @@ -143,10 +142,8 @@ func (b *backend) DeleteMsgWithExternalID(ctx context.Context, channel courier.C // NewIncomingMsg creates a new message from the given params func (b *backend) NewIncomingMsg(channel courier.Channel, urn urns.URN, text string, clog *courier.ChannelLog) courier.Msg { - // remove any control characters - text = utils.CleanString(text) + text = dbutil.ToValidUTF8(text) // strip out invalid UTF8 and NULL chars - // create our msg msg := newMsg(MsgIncoming, channel, urn, text, clog) // set received on to now diff --git a/go.mod b/go.mod index 3fed43a26..e208bdc19 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.7 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.32.2 + github.com/nyaruka/gocommon v1.33.0 github.com/nyaruka/null v1.2.0 github.com/nyaruka/redisx v0.2.2 github.com/patrickmn/go-cache v2.1.0+incompatible diff --git a/go.sum b/go.sum index a1234e8f2..c9ff8a604 100644 --- a/go.sum +++ b/go.sum @@ -76,8 +76,8 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.32.2 h1:SsrVBnccJ9ZcRApAYlyO/lyFG3rREb6d0x2K9Pgtk3s= -github.com/nyaruka/gocommon v1.32.2/go.mod h1:k03R7UY1IX65qPEncv7MgvQx7BZ2laR+ikN1GQjTMbY= +github.com/nyaruka/gocommon v1.33.0 h1:X68AFxyPZHokumiGwAq0CqkU3/j7ZzGrjxTu9azH2ko= +github.com/nyaruka/gocommon v1.33.0/go.mod h1:k03R7UY1IX65qPEncv7MgvQx7BZ2laR+ikN1GQjTMbY= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= diff --git a/handlers/clickatell/clickatell.go b/handlers/clickatell/clickatell.go index ceae54e5a..054f6c226 100644 --- a/handlers/clickatell/clickatell.go +++ b/handlers/clickatell/clickatell.go @@ -15,7 +15,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" ) var ( @@ -143,7 +142,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } // build our msg - msg := h.Backend().NewIncomingMsg(channel, urn, utils.CleanString(text), clog).WithReceivedOn(date.UTC()).WithExternalID(payload.MessageID) + msg := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithReceivedOn(date.UTC()).WithExternalID(payload.MessageID) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/handlers/highconnection/highconnection.go b/handlers/highconnection/highconnection.go index 8c88021df..43f3f030c 100644 --- a/handlers/highconnection/highconnection.go +++ b/handlers/highconnection/highconnection.go @@ -10,7 +10,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" ) var ( @@ -74,7 +73,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w text, _ = new(mime.WordDecoder).DecodeHeader(text) // build our Message - msg := h.Backend().NewIncomingMsg(channel, urn, utils.CleanString(text), clog).WithReceivedOn(date.UTC()) + msg := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithReceivedOn(date.UTC()) // and finally write our message return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) diff --git a/utils/misc.go b/utils/misc.go index 6a5ee38d0..593aa8636 100644 --- a/utils/misc.go +++ b/utils/misc.go @@ -7,8 +7,6 @@ import ( "encoding/hex" "net/url" "path" - "regexp" - "strings" "unicode/utf8" validator "gopkg.in/go-playground/validator.v9" @@ -74,33 +72,6 @@ func StringArrayContains(s []string, e string) bool { return false } -var invalidChars = regexp.MustCompile("([\u0000-\u0008]|[\u000B-\u000C]|[\u000E-\u001F])") - -// CleanString removes any control characters from the passed in string -func CleanString(s string) string { - cleaned := invalidChars.ReplaceAllString(s, "") - - // check whether this is valid UTF8 - if !utf8.ValidString(cleaned) || strings.Contains(cleaned, "\x00") { - v := make([]rune, 0, len(cleaned)) - for i, r := range s { - if r == utf8.RuneError { - _, size := utf8.DecodeRuneInString(s[i:]) - if size == 1 { - continue - } - } - - if r != 0 { - v = append(v, r) - } - } - cleaned = string(v) - } - - return cleaned -} - // BasePathForURL, parse static URL, and return filename + format func BasePathForURL(rawURL string) (string, error) { parsedURL, err := url.Parse(rawURL) diff --git a/utils/misc_test.go b/utils/misc_test.go index 6e760b825..9dc055266 100644 --- a/utils/misc_test.go +++ b/utils/misc_test.go @@ -1,7 +1,6 @@ package utils_test import ( - "net/url" "testing" "github.com/nyaruka/courier/utils" @@ -25,17 +24,6 @@ func TestStringArrayContains(t *testing.T) { assert.True(t, utils.StringArrayContains([]string{"a", "b", "x", "y"}, "x")) } -func TestCleanString(t *testing.T) { - assert.Equal(t, "\x41hello", utils.CleanString("\x02\x41hello")) - assert.Equal(t, "😅 happy!", utils.CleanString("😅 happy!")) - assert.Equal(t, "Hello There", utils.CleanString("Hello \x00 There")) - assert.Equal(t, "Hello There", utils.CleanString("Hello There\u0000")) - assert.Equal(t, "Hello z There", utils.CleanString("Hello \xc5z There")) - - text, _ := url.PathUnescape("hi%1C%00%00%00%00%00%07%E0%00") - assert.Equal(t, "hi\x1c\a", utils.CleanString(text)) -} - func TestURLGetFile(t *testing.T) { test1, err := utils.BasePathForURL("https://example.com/test.pdf") assert.Equal(t, nil, err) From 1a7797a3d33cab96baf1da65728679be8b306591 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 18 Nov 2022 15:50:02 -0500 Subject: [PATCH 272/294] Ensure that URN and contact name are valid utf8 before trying to write to DB --- backends/rapidpro/backend.go | 1 + backends/rapidpro/contact.go | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index a2f511203..8cf86d3f1 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -142,6 +142,7 @@ func (b *backend) DeleteMsgWithExternalID(ctx context.Context, channel courier.C // NewIncomingMsg creates a new message from the given params func (b *backend) NewIncomingMsg(channel courier.Channel, urn urns.URN, text string, clog *courier.ChannelLog) courier.Msg { + urn = urns.URN(dbutil.ToValidUTF8(string(urn))) text = dbutil.ToValidUTF8(text) // strip out invalid UTF8 and NULL chars msg := newMsg(MsgIncoming, channel, urn, text, clog) diff --git a/backends/rapidpro/contact.go b/backends/rapidpro/contact.go index 3c1fef469..664e6bda2 100644 --- a/backends/rapidpro/contact.go +++ b/backends/rapidpro/contact.go @@ -139,13 +139,13 @@ func contactForURN(ctx context.Context, b *backend, org OrgID, channel *DBChanne if handler != nil { describer, isDescriber := handler.(courier.URNDescriber) if isDescriber { - atts, err := describer.DescribeURN(ctx, channel, urn, clog) + attrs, err := describer.DescribeURN(ctx, channel, urn, clog) // in the case of errors, we log the error but move onwards anyways if err != nil { logrus.WithField("channel_uuid", channel.UUID()).WithField("channel_type", channel.ChannelType()).WithField("urn", urn).WithError(err).Error("unable to describe URN") } else { - name = atts["name"] + name = attrs["name"] } } } @@ -156,7 +156,7 @@ func contactForURN(ctx context.Context, b *backend, org OrgID, channel *DBChanne name = string([]rune(name)[:127]) } - contact.Name_ = null.String(name) + contact.Name_ = null.String(dbutil.ToValidUTF8(name)) } } From 9fa192a69d6786dfa103c130c3e05e3da99016cd Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 18 Nov 2022 17:02:39 -0500 Subject: [PATCH 273/294] Update CHANGELOG.md for v7.5.61 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1e5220df..93f6be002 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +v7.5.61 (2022-11-18) +------------------------- + * Ensure that URN and contact name are valid utf8 before trying to write to DB + * Update to latest gocommon which provides dbutil.ToValidUTF8 + * Resolve error codes to messages for Twilio and Vonage and log errors for Twilio DLRs + * Don't add returned err to channel log if it has logged errors already + v7.5.60 ---------- * Allow msg id to be passed to fetch attachment requests and saved on the channel log From c81f63d2c57106075f3b2ac7ba800d5cf5376326 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 21 Nov 2022 08:05:20 -0500 Subject: [PATCH 274/294] Update CI test versions --- .github/workflows/ci.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fabc85152..398768be8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,10 +5,9 @@ env: jobs: test: name: Test - strategy: - matrix: - redis-version: ["5.0.6", "6.2"] - pg-version: ["13", "14"] + env: + pg-version: "14" + redis-version: "6.2" runs-on: ubuntu-latest steps: - name: Checkout code @@ -17,12 +16,12 @@ jobs: - name: Install Redis uses: zhulik/redis-action@v1.0.0 with: - redis version: ${{ matrix.redis-version }} + redis version: ${{ matrix.env-version }} - name: Install PostgreSQL uses: harmon758/postgresql-action@v1 with: - postgresql version: ${{ matrix.pg-version }} + postgresql version: ${{ env.pg-version }} postgresql db: courier_test postgresql user: courier postgresql password: courier From 9ad5a4a068acc42872329231f7abc12e1b46b097 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 21 Nov 2022 08:09:18 -0500 Subject: [PATCH 275/294] Fix redis version in ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 398768be8..e4e2e2085 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - name: Install Redis uses: zhulik/redis-action@v1.0.0 with: - redis version: ${{ matrix.env-version }} + redis version: ${{ env.redis-version }} - name: Install PostgreSQL uses: harmon758/postgresql-action@v1 From caae7a0f7927541f7dadc8f232f477e644379021 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Mon, 21 Nov 2022 15:49:20 +0200 Subject: [PATCH 276/294] Add logs for WhatsApp Cloud specific errors --- handlers/facebookapp/facebookapp.go | 40 ++++++++++++-- handlers/facebookapp/facebookapp_test.go | 51 +++++++++++++++++ .../facebookapp/testdata/wac/errorErrors.json | 34 ++++++++++++ .../facebookapp/testdata/wac/errorMsg.json | 46 ++++++++++++++++ .../facebookapp/testdata/wac/errorStatus.json | 55 +++++++++++++++++++ 5 files changed, 221 insertions(+), 5 deletions(-) create mode 100644 handlers/facebookapp/testdata/wac/errorErrors.json create mode 100644 handlers/facebookapp/testdata/wac/errorMsg.json create mode 100644 handlers/facebookapp/testdata/wac/errorStatus.json diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index b9d29541b..dab6d9d06 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -186,6 +186,10 @@ type moPayload struct { Title string `json:"title"` } `json:"list_reply,omitempty"` } `json:"interactive,omitempty"` + Errors []struct { + Code int `json:"code"` + Title string `json:"title"` + } `json:"errors"` } `json:"messages"` Statuses []struct { ID string `json:"id"` @@ -204,6 +208,10 @@ type moPayload struct { Billable bool `json:"billable"` Category string `json:"category"` } `json:"pricing"` + Errors []struct { + Code int `json:"code"` + Title string `json:"title"` + } `json:"errors"` } `json:"statuses"` Errors []struct { Code int `json:"code"` @@ -439,6 +447,11 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri return nil, nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } + for _, msg_error := range msg.Errors { + codeAsStr := strconv.Itoa(int(msg_error.Code)) + clog.Error(courier.ErrorServiceSpecific("whatsapp_cloud", codeAsStr, msg_error.Title)) + } + text := "" mediaURL := "" @@ -470,6 +483,7 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri } else { // we received a message type we do not support. courier.LogRequestError(r, channel, fmt.Errorf("unsupported message type %s", msg.Type)) + continue } // create our message @@ -509,6 +523,11 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri continue } + for _, status_error := range status.Errors { + codeAsStr := strconv.Itoa(int(status_error.Code)) + clog.Error(courier.ErrorServiceSpecific("whatsapp_cloud", codeAsStr, status_error.Title)) + } + event := h.Backend().NewMsgStatusForExternalID(channel, status.ID, msgStatus, clog) err := h.Backend().WriteMsgStatus(ctx, event) @@ -527,6 +546,11 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri } + for _, ch_error := range change.Value.Errors { + codeAsStr := strconv.Itoa(int(ch_error.Code)) + clog.Error(courier.ErrorServiceSpecific("whatsapp_cloud", codeAsStr, ch_error.Title)) + } + } } @@ -1063,6 +1087,10 @@ type wacMTResponse struct { Messages []*struct { ID string `json:"id"` } `json:"messages"` + Error struct { + Message string `json:"message"` + Code int `json:"code"` + } `json:"error"` } func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { @@ -1361,11 +1389,7 @@ func requestWAC(payload wacMTPayload, accessToken string, status courier.MsgStat req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, clog) - if err != nil || resp.StatusCode/100 != 2 { - return status, nil - } - + _, respBody, _ := handlers.RequestHTTP(req, clog) respPayload := &wacMTResponse{} err = json.Unmarshal(respBody, respPayload) if err != nil { @@ -1373,6 +1397,12 @@ func requestWAC(payload wacMTPayload, accessToken string, status courier.MsgStat return status, nil } + if respPayload.Error.Code != 0 { + codeAsStr := strconv.Itoa(int(respPayload.Error.Code)) + clog.Error(courier.ErrorServiceSpecific("whatsapp_cloud", codeAsStr, respPayload.Error.Message)) + return status, nil + } + externalID := respPayload.Messages[0].ID if zeroIndex && externalID != "" { status.SetExternalID(externalID) diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index a17c109e0..938176171 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -704,6 +704,26 @@ var testCasesWAC = []ChannelHandleTestCase{ NoInvalidChannelCheck: true, PrepRequest: addInvalidSignature, }, + { + Label: "Receive Message WAC with error message", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/errorMsg.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("whatsapp_cloud", "131051", "Unsupported message type")}, + NoInvalidChannelCheck: true, + PrepRequest: addValidSignature, + }, + { + Label: "Receive error message", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/errorErrors.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("whatsapp_cloud", "0", "We were unable to authenticate the app user")}, + NoInvalidChannelCheck: true, + PrepRequest: addValidSignature, + }, { Label: "Receive Valid Status", URL: wacReceiveURL, @@ -714,6 +734,17 @@ var testCasesWAC = []ChannelHandleTestCase{ ExpectedExternalID: "external_id", PrepRequest: addValidSignature, }, + { + Label: "Receive Valid Status with error message", + URL: wacReceiveURL, + Data: string(test.ReadFile("./testdata/wac/errorStatus.json")), + ExpectedRespStatus: 200, + ExpectedBodyContains: `"type":"status"`, + ExpectedMsgStatus: "F", + ExpectedExternalID: "external_id", + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("whatsapp_cloud", "131014", "Request for url https://URL.jpg failed with error: 404 (Not Found)")}, + PrepRequest: addValidSignature, + }, { Label: "Receive Invalid Status", URL: wacReceiveURL, @@ -1367,6 +1398,26 @@ var SendTestCasesWAC = []ChannelSendTestCase{ ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, }, + { + Label: "Error Bad JSON", + MsgText: "Error", + MsgURN: "whatsapp:250788123123", + MockResponseBody: `bad json`, + MockResponseStatus: 403, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to unmarshal response body", "")}, + ExpectedMsgStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error", + MsgText: "Error", + MsgURN: "whatsapp:250788123123", + MockResponseBody: `{ "error": {"message": "(#130429) Rate limit hit","code": 130429 }}`, + MockResponseStatus: 403, + ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("whatsapp_cloud", "130429", "(#130429) Rate limit hit")}, + ExpectedMsgStatus: "E", + SendPrep: setSendURL, + }, } func TestSending(t *testing.T) { diff --git a/handlers/facebookapp/testdata/wac/errorErrors.json b/handlers/facebookapp/testdata/wac/errorErrors.json new file mode 100644 index 000000000..42e86216f --- /dev/null +++ b/handlers/facebookapp/testdata/wac/errorErrors.json @@ -0,0 +1,34 @@ +{ + "object": "whatsapp_business_account", + "entry": [ + { + "id": "8856996819413533", + "changes": [ + { + "value": { + "messaging_product": "whatsapp", + "metadata": { + "display_phone_number": "+250 788 123 200", + "phone_number_id": "12345" + }, + "contacts": [ + { + "profile": { + "name": "Kerry Fisher" + }, + "wa_id": "5678" + } + ], + "errors": [ + { + "code": 0, + "title": "We were unable to authenticate the app user" + } + ] + }, + "field": "messages" + } + ] + } + ] +} \ No newline at end of file diff --git a/handlers/facebookapp/testdata/wac/errorMsg.json b/handlers/facebookapp/testdata/wac/errorMsg.json new file mode 100644 index 000000000..099dc62aa --- /dev/null +++ b/handlers/facebookapp/testdata/wac/errorMsg.json @@ -0,0 +1,46 @@ +{ + "object": "whatsapp_business_account", + "entry": [ + { + "id": "8856996819413533", + "changes": [ + { + "value": { + "messaging_product": "whatsapp", + "metadata": { + "display_phone_number": "+250 788 123 200", + "phone_number_id": "12345" + }, + "contacts": [ + { + "profile": { + "name": "Kerry Fisher" + }, + "wa_id": "5678" + } + ], + "messages": [ + { + "from": "5678", + "id": "external_id", + "timestamp": "1454119029", + "text": { + "body": "Hello World" + }, + "type": "unsupported", + "errors": [ + { + "code": 131051, + "details": "Message type is not currently supported", + "title": "Unsupported message type" + } + ] + } + ] + }, + "field": "messages" + } + ] + } + ] +} \ No newline at end of file diff --git a/handlers/facebookapp/testdata/wac/errorStatus.json b/handlers/facebookapp/testdata/wac/errorStatus.json new file mode 100644 index 000000000..95f03649d --- /dev/null +++ b/handlers/facebookapp/testdata/wac/errorStatus.json @@ -0,0 +1,55 @@ +{ + "object": "whatsapp_business_account", + "entry": [ + { + "id": "8856996819413533", + "changes": [ + { + "value": { + "messaging_product": "whatsapp", + "metadata": { + "display_phone_number": "+250 788 123 200", + "phone_number_id": "12345" + }, + "contacts": [ + { + "profile": { + "name": "Kerry Fisher" + }, + "wa_id": "5678" + } + ], + "statuses": [ + { + "id": "external_id", + "recipient_id": "5678", + "status": "failed", + "timestamp": "1454119029", + "type": "message", + "conversation": { + "id": "CONVERSATION_ID", + "expiration_timestamp": 1454119029, + "origin": { + "type": "referral_conversion" + } + }, + "pricing": { + "pricing_model": "CBP", + "billable": false, + "category": "referral_conversion" + }, + "errors": [ + { + "code": 131014, + "title": "Request for url https://URL.jpg failed with error: 404 (Not Found)" + } + ] + } + ] + }, + "field": "messages" + } + ] + } + ] +} \ No newline at end of file From 73c7765c56613d3bab5fbb4183b87d02a4db22ab Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Mon, 21 Nov 2022 16:44:48 +0200 Subject: [PATCH 277/294] Adjust variables name --- handlers/facebookapp/facebookapp.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index dab6d9d06..bc922e092 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -447,9 +447,9 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri return nil, nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } - for _, msg_error := range msg.Errors { - codeAsStr := strconv.Itoa(int(msg_error.Code)) - clog.Error(courier.ErrorServiceSpecific("whatsapp_cloud", codeAsStr, msg_error.Title)) + for _, msgError := range msg.Errors { + codeAsStr := strconv.Itoa(int(msgError.Code)) + clog.Error(courier.ErrorServiceSpecific("whatsapp_cloud", codeAsStr, msgError.Title)) } text := "" @@ -523,9 +523,9 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri continue } - for _, status_error := range status.Errors { - codeAsStr := strconv.Itoa(int(status_error.Code)) - clog.Error(courier.ErrorServiceSpecific("whatsapp_cloud", codeAsStr, status_error.Title)) + for _, statusError := range status.Errors { + codeAsStr := strconv.Itoa(int(statusError.Code)) + clog.Error(courier.ErrorServiceSpecific("whatsapp_cloud", codeAsStr, statusError.Title)) } event := h.Backend().NewMsgStatusForExternalID(channel, status.ID, msgStatus, clog) @@ -546,9 +546,9 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri } - for _, ch_error := range change.Value.Errors { - codeAsStr := strconv.Itoa(int(ch_error.Code)) - clog.Error(courier.ErrorServiceSpecific("whatsapp_cloud", codeAsStr, ch_error.Title)) + for _, chError := range change.Value.Errors { + codeAsStr := strconv.Itoa(int(chError.Code)) + clog.Error(courier.ErrorServiceSpecific("whatsapp_cloud", codeAsStr, chError.Title)) } } From 3193d4658b1e45a9ac225c5a30460c4fc81ca78a Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 21 Nov 2022 12:35:50 -0500 Subject: [PATCH 278/294] Rework channel log errors to have separate code and ext_code fields to remove the need for namespaces --- backends/rapidpro/channel_log.go | 5 +- backends/rapidpro/msg.go | 2 +- channel_log.go | 37 +++++++----- channel_log_test.go | 72 ++++++++++++++---------- handler_test.go | 2 +- handlers/blackmyna/blackmyna_test.go | 2 +- handlers/dart/dart.go | 2 +- handlers/dart/dart_test.go | 4 +- handlers/facebookapp/facebookapp.go | 14 ++--- handlers/facebookapp/facebookapp_test.go | 12 ++-- handlers/freshchat/freshchat.go | 2 +- handlers/macrokiosk/macrokiosk_test.go | 2 +- handlers/mblox/mblox_test.go | 2 +- handlers/mtarget/mtarget_test.go | 2 +- handlers/nexmo/nexmo.go | 4 +- handlers/nexmo/nexmo_test.go | 6 +- handlers/novo/novo_test.go | 4 +- handlers/plivo/plivo_test.go | 2 +- handlers/slack/slack_test.go | 2 +- handlers/telegram/telegram.go | 2 +- handlers/telegram/telegram_test.go | 2 +- handlers/test.go | 2 +- handlers/twiml/twiml.go | 2 +- handlers/twiml/twiml_test.go | 16 +++--- handlers/twitter/twitter_test.go | 4 +- handlers/viber/viber.go | 2 +- handlers/viber/viber_test.go | 4 +- handlers/whatsapp/whatsapp.go | 2 +- handlers/whatsapp/whatsapp_test.go | 2 +- handlers/zenviaold/zenviaold_test.go | 2 +- sender.go | 2 +- test/handler.go | 2 +- 32 files changed, 119 insertions(+), 103 deletions(-) diff --git a/backends/rapidpro/channel_log.go b/backends/rapidpro/channel_log.go index 1eb3feb55..dbf5fde78 100644 --- a/backends/rapidpro/channel_log.go +++ b/backends/rapidpro/channel_log.go @@ -32,8 +32,9 @@ func (l *ChannelLog) RowID() string { } type channelError struct { - Message string `json:"message"` Code string `json:"code"` + ExtCode string `json:"ext_code,omitempty"` + Message string `json:"message"` } // queues the passed in channel log the committer, we do not queue on errors but instead just throw away the log @@ -53,7 +54,7 @@ func queueChannelLog(ctx context.Context, b *backend, clog *courier.ChannelLog) errors := make([]channelError, len(clog.Errors())) for i, e := range clog.Errors() { - errors[i] = channelError{Message: e.Message(), Code: e.Code()} + errors[i] = channelError{Code: e.Code(), ExtCode: e.ExtCode(), Message: e.Message()} } // create our value for committing diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index cf456173c..6c062a0df 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -59,7 +59,7 @@ func writeMsg(ctx context.Context, b *backend, msg courier.Msg, clog *courier.Ch if strings.HasPrefix(attURL, "data:") { attData, err := base64.StdEncoding.DecodeString(attURL[5:]) if err != nil { - clog.Error(courier.NewChannelError("Unable to decode attachment data.", "")) + clog.Error(courier.ErrorAttachmentNotDecodable()) return errors.Wrap(err, "unable to decode attachment data") } diff --git a/channel_log.go b/channel_log.go index fb7b27e18..330c41105 100644 --- a/channel_log.go +++ b/channel_log.go @@ -29,28 +29,29 @@ const ( ) type ChannelError struct { - message string code string + extCode string + message string } -func NewChannelError(message, code string) *ChannelError { - return &ChannelError{message: message, code: code} +func NewChannelError(code, extCode, message string, args ...any) *ChannelError { + return &ChannelError{code: code, extCode: extCode, message: fmt.Sprintf(message, args...)} } func ErrorResponseStatusCode() *ChannelError { - return NewChannelError("Unexpected response status code.", "core:response_status_code") + return NewChannelError("response_status_code", "", "Unexpected response status code.") } func ErrorResponseUnparseable(format string) *ChannelError { - return NewChannelError(fmt.Sprintf("Unable to parse response as %s.", format), "core:response_unparseable") + return NewChannelError("response_unparseable", "", "Unable to parse response as %s.", format) } func ErrorResponseUnexpected(expected string) *ChannelError { - return NewChannelError(fmt.Sprintf("Expected response to be '%s'.", expected), "core:response_unexpected") + return NewChannelError("response_unexpected", "", "Expected response to be '%s'.", expected) } func ErrorResponseValueMissing(key string) *ChannelError { - return NewChannelError(fmt.Sprintf("Unable to find '%s' response.", key), "core:response_value_missing") + return NewChannelError("response_value_missing", "", "Unable to find '%s' response.", key) } func ErrorResponseValueUnexpected(key string, expected ...string) *ChannelError { @@ -58,22 +59,26 @@ func ErrorResponseValueUnexpected(key string, expected ...string) *ChannelError for i := range expected { es[i] = fmt.Sprintf("'%s'", expected[i]) } - return NewChannelError(fmt.Sprintf("Expected '%s' in response to be %s.", key, strings.Join(es, " or ")), "core:response_value_unexpected") + return NewChannelError("response_value_unexpected", "", "Expected '%s' in response to be %s.", key, strings.Join(es, " or ")) +} + +func ErrorMediaUnsupported(contentType string) *ChannelError { + return NewChannelError("media_unsupported", "", "Unsupported attachment media type: %s.", contentType) } -func ErrorUnsupportedMedia(contentType string) *ChannelError { - return NewChannelError(fmt.Sprintf("Unsupported attachment media type: %s.", contentType), "core:media_unsupported_type") +func ErrorAttachmentNotDecodable() *ChannelError { + return NewChannelError("attachment_not_decodable", "", "Unable to decode embedded attachment data.") } -func ErrorServiceSpecific(ns, code, message string) *ChannelError { +func ErrorExternal(code, message string) *ChannelError { if message == "" { message = fmt.Sprintf("Service specific error: %s.", code) } - return NewChannelError(message, fmt.Sprintf("%s:%s", ns, code)) + return NewChannelError("external", code, message) } func (e *ChannelError) Redact(r stringsx.Redactor) *ChannelError { - return &ChannelError{message: r(e.message), code: r(e.code)} + return &ChannelError{code: e.code, extCode: e.extCode, message: r(e.message)} } func (e *ChannelError) Message() string { @@ -84,6 +89,10 @@ func (e *ChannelError) Code() string { return e.code } +func (e *ChannelError) ExtCode() string { + return e.extCode +} + // ChannelLog stores the HTTP traces and errors generated by an interaction with a channel. type ChannelLog struct { uuid ChannelLogUUID @@ -144,7 +153,7 @@ func (l *ChannelLog) Error(e *ChannelError) { // Deprecated: channel handlers should add user-facing error messages via .Error() instead func (l *ChannelLog) RawError(err error) { - l.Error(NewChannelError(err.Error(), "")) + l.Error(NewChannelError("", "", err.Error())) } func (l *ChannelLog) End() { diff --git a/channel_log_test.go b/channel_log_test.go index 17516bddc..c2f08264f 100644 --- a/channel_log_test.go +++ b/channel_log_test.go @@ -41,7 +41,7 @@ func TestChannelLog(t *testing.T) { assert.EqualError(t, err, "unable to connect to server") clog.HTTP(trace) - clog.Error(courier.NewChannelError("Something not right", "twilio:23456")) + clog.Error(courier.NewChannelError("not_right", "", "Something not right")) clog.RawError(errors.New("this is an error")) clog.End() @@ -66,8 +66,9 @@ func TestChannelLog(t *testing.T) { assert.Equal(t, "", hlog2.Response) err1 := clog.Errors()[0] + assert.Equal(t, "not_right", err1.Code()) + assert.Equal(t, "", err1.ExtCode()) assert.Equal(t, "Something not right", err1.Message()) - assert.Equal(t, "twilio:23456", err1.Code()) err2 := clog.Errors()[1] assert.Equal(t, "this is an error", err2.Message()) @@ -83,58 +84,67 @@ func TestChannelLog(t *testing.T) { func TestChannelErrors(t *testing.T) { tcs := []struct { err *courier.ChannelError - expectedMessage string expectedCode string + expectedExtCode string + expectedMessage string }{ { - courier.ErrorResponseStatusCode(), - "Unexpected response status code.", - "core:response_status_code", + err: courier.ErrorResponseStatusCode(), + expectedCode: "response_status_code", + expectedMessage: "Unexpected response status code.", + }, + { + err: courier.ErrorResponseUnparseable("FOO"), + expectedCode: "response_unparseable", + expectedMessage: "Unable to parse response as FOO.", }, { - courier.ErrorResponseUnparseable("FOO"), - "Unable to parse response as FOO.", - "core:response_unparseable", + err: courier.ErrorResponseUnexpected("all good!"), + expectedCode: "response_unexpected", + expectedMessage: "Expected response to be 'all good!'.", }, { - courier.ErrorResponseUnexpected("all good!"), - "Expected response to be 'all good!'.", - "core:response_unexpected", + err: courier.ErrorResponseValueMissing("id"), + expectedCode: "response_value_missing", + expectedMessage: "Unable to find 'id' response.", }, { - courier.ErrorResponseValueMissing("id"), - "Unable to find 'id' response.", - "core:response_value_missing", + err: courier.ErrorResponseValueUnexpected("status", "SUCCESS"), + expectedCode: "response_value_unexpected", + expectedMessage: "Expected 'status' in response to be 'SUCCESS'.", }, { - courier.ErrorResponseValueUnexpected("status", "SUCCESS"), - "Expected 'status' in response to be 'SUCCESS'.", - "core:response_value_unexpected", + err: courier.ErrorResponseValueUnexpected("status", "SUCCESS", "OK"), + expectedCode: "response_value_unexpected", + expectedMessage: "Expected 'status' in response to be 'SUCCESS' or 'OK'.", }, { - courier.ErrorResponseValueUnexpected("status", "SUCCESS", "OK"), - "Expected 'status' in response to be 'SUCCESS' or 'OK'.", - "core:response_value_unexpected", + err: courier.ErrorMediaUnsupported("image/tiff"), + expectedCode: "media_unsupported", + expectedMessage: "Unsupported attachment media type: image/tiff.", }, { - courier.ErrorUnsupportedMedia("image/tiff"), - "Unsupported attachment media type: image/tiff.", - "core:media_unsupported_type", + err: courier.ErrorAttachmentNotDecodable(), + expectedCode: "attachment_not_decodable", + expectedMessage: "Unable to decode embedded attachment data.", }, { - courier.ErrorServiceSpecific("twilio", "20002", "Invalid FriendlyName."), - "Invalid FriendlyName.", - "twilio:20002", + err: courier.ErrorExternal("20002", "Invalid FriendlyName."), + expectedCode: "external", + expectedExtCode: "20002", + expectedMessage: "Invalid FriendlyName.", }, { - courier.ErrorServiceSpecific("twilio", "20003", ""), - "Service specific error: 20003.", - "twilio:20003", + err: courier.ErrorExternal("20003", ""), + expectedCode: "external", + expectedExtCode: "20003", + expectedMessage: "Service specific error: 20003.", }, } for _, tc := range tcs { - assert.Equal(t, tc.expectedMessage, tc.err.Message()) assert.Equal(t, tc.expectedCode, tc.err.Code()) + assert.Equal(t, tc.expectedExtCode, tc.err.ExtCode()) + assert.Equal(t, tc.expectedMessage, tc.err.Message()) } } diff --git a/handler_test.go b/handler_test.go index 395a4bd0e..281881f4f 100644 --- a/handler_test.go +++ b/handler_test.go @@ -73,7 +73,7 @@ func TestHandling(t *testing.T) { assert.Len(mb.WrittenChannelLogs(), 1) clog := mb.WrittenChannelLogs()[0] - assert.Equal([]*courier.ChannelError{courier.NewChannelError("contains ********** seeds", "")}, clog.Errors()) + assert.Equal([]*courier.ChannelError{courier.NewChannelError("seeds", "", "contains ********** seeds")}, clog.Errors()) assert.Len(clog.HTTPLogs(), 1) diff --git a/handlers/blackmyna/blackmyna_test.go b/handlers/blackmyna/blackmyna_test.go index 8881fc404..d0d666dc2 100644 --- a/handlers/blackmyna/blackmyna_test.go +++ b/handlers/blackmyna/blackmyna_test.go @@ -122,7 +122,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "tel:+250788383383", MockResponseBody: `{ "error": "failed" }`, MockResponseStatus: 200, - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("no external id returned in body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("", "", "no external id returned in body")}, ExpectedPostParams: map[string]string{"message": `No External ID`, "address": "+250788383383", "senderaddress": "2020"}, ExpectedMsgStatus: "E", SendPrep: setSendURL, diff --git a/handlers/dart/dart.go b/handlers/dart/dart.go index 5945ae099..661c1390f 100644 --- a/handlers/dart/dart.go +++ b/handlers/dart/dart.go @@ -192,7 +192,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann responseCode := stringsx.Truncate(string(respBody), 3) if responseCode != "000" { - clog.Error(courier.ErrorServiceSpecific("dart", responseCode, errorCodes[responseCode])) + clog.Error(courier.ErrorExternal(responseCode, errorCodes[responseCode])) return status, nil } diff --git a/handlers/dart/dart_test.go b/handlers/dart/dart_test.go index a62112043..13723bedd 100644 --- a/handlers/dart/dart_test.go +++ b/handlers/dart/dart_test.go @@ -147,7 +147,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("dart", "001", "Authentication error.")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("001", "Authentication error.")}, SendPrep: setSendURL, }, { @@ -158,7 +158,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedURLParams: map[string]string{"message": "Simple Message", "sendto": "250788383383", "original": "2020", "userid": "Username", "password": "Password", "dcs": "0", "udhl": "0", "messageid": "10"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("dart", "101", "Account expired or invalid parameters.")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("101", "Account expired or invalid parameters.")}, SendPrep: setSendURL, }, } diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index bc922e092..77b109659 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -448,8 +448,7 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri } for _, msgError := range msg.Errors { - codeAsStr := strconv.Itoa(int(msgError.Code)) - clog.Error(courier.ErrorServiceSpecific("whatsapp_cloud", codeAsStr, msgError.Title)) + clog.Error(courier.ErrorExternal(strconv.Itoa(msgError.Code), msgError.Title)) } text := "" @@ -524,8 +523,7 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri } for _, statusError := range status.Errors { - codeAsStr := strconv.Itoa(int(statusError.Code)) - clog.Error(courier.ErrorServiceSpecific("whatsapp_cloud", codeAsStr, statusError.Title)) + clog.Error(courier.ErrorExternal(strconv.Itoa(statusError.Code), statusError.Title)) } event := h.Backend().NewMsgStatusForExternalID(channel, status.ID, msgStatus, clog) @@ -547,8 +545,7 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri } for _, chError := range change.Value.Errors { - codeAsStr := strconv.Itoa(int(chError.Code)) - clog.Error(courier.ErrorServiceSpecific("whatsapp_cloud", codeAsStr, chError.Title)) + clog.Error(courier.ErrorExternal(strconv.Itoa(chError.Code), chError.Title)) } } @@ -1393,13 +1390,12 @@ func requestWAC(payload wacMTPayload, accessToken string, status courier.MsgStat respPayload := &wacMTResponse{} err = json.Unmarshal(respBody, respPayload) if err != nil { - clog.RawError(errors.Errorf("unable to unmarshal response body")) + clog.Error(courier.ErrorResponseUnparseable("JSON")) return status, nil } if respPayload.Error.Code != 0 { - codeAsStr := strconv.Itoa(int(respPayload.Error.Code)) - clog.Error(courier.ErrorServiceSpecific("whatsapp_cloud", codeAsStr, respPayload.Error.Message)) + clog.Error(courier.ErrorExternal(strconv.Itoa(respPayload.Error.Code), respPayload.Error.Message)) return status, nil } diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 938176171..7044148f5 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -710,7 +710,7 @@ var testCasesWAC = []ChannelHandleTestCase{ Data: string(test.ReadFile("./testdata/wac/errorMsg.json")), ExpectedRespStatus: 200, ExpectedBodyContains: "Handled", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("whatsapp_cloud", "131051", "Unsupported message type")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("131051", "Unsupported message type")}, NoInvalidChannelCheck: true, PrepRequest: addValidSignature, }, @@ -720,7 +720,7 @@ var testCasesWAC = []ChannelHandleTestCase{ Data: string(test.ReadFile("./testdata/wac/errorErrors.json")), ExpectedRespStatus: 200, ExpectedBodyContains: "Handled", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("whatsapp_cloud", "0", "We were unable to authenticate the app user")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("0", "We were unable to authenticate the app user")}, NoInvalidChannelCheck: true, PrepRequest: addValidSignature, }, @@ -742,7 +742,7 @@ var testCasesWAC = []ChannelHandleTestCase{ ExpectedBodyContains: `"type":"status"`, ExpectedMsgStatus: "F", ExpectedExternalID: "external_id", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("whatsapp_cloud", "131014", "Request for url https://URL.jpg failed with error: 404 (Not Found)")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("131014", "Request for url https://URL.jpg failed with error: 404 (Not Found)")}, PrepRequest: addValidSignature, }, { @@ -1274,7 +1274,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MsgText: "templated message", MsgURN: "whatsapp:250788123123", MsgMetadata: json.RawMessage(`{"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}}`), - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError(`unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("", "", `unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`)}, }, { Label: "Interactive Button Message Send", @@ -1404,7 +1404,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MsgURN: "whatsapp:250788123123", MockResponseBody: `bad json`, MockResponseStatus: 403, - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to unmarshal response body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseUnparseable("JSON")}, ExpectedMsgStatus: "E", SendPrep: setSendURL, }, @@ -1414,7 +1414,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MsgURN: "whatsapp:250788123123", MockResponseBody: `{ "error": {"message": "(#130429) Rate limit hit","code": 130429 }}`, MockResponseStatus: 403, - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("whatsapp_cloud", "130429", "(#130429) Rate limit hit")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("130429", "(#130429) Rate limit hit")}, ExpectedMsgStatus: "E", SendPrep: setSendURL, }, diff --git a/handlers/freshchat/freshchat.go b/handlers/freshchat/freshchat.go index a8e1352d4..cc48a16bb 100644 --- a/handlers/freshchat/freshchat.go +++ b/handlers/freshchat/freshchat.go @@ -148,7 +148,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann msgimage.Image = &Image{URL: mediaURL} payload.Messages[0].MessageParts = append(payload.Messages[0].MessageParts, *msgimage) default: - clog.Error(courier.ErrorUnsupportedMedia(mediaType)) + clog.Error(courier.ErrorMediaUnsupported(mediaType)) } } diff --git a/handlers/macrokiosk/macrokiosk_test.go b/handlers/macrokiosk/macrokiosk_test.go index fe2926a0f..d534f50b9 100644 --- a/handlers/macrokiosk/macrokiosk_test.go +++ b/handlers/macrokiosk/macrokiosk_test.go @@ -110,7 +110,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedMsgStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to parse response body from Macrokiosk", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("", "", "unable to parse response body from Macrokiosk")}, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", diff --git a/handlers/mblox/mblox_test.go b/handlers/mblox/mblox_test.go index 97d78f7fd..bd1b21dc8 100644 --- a/handlers/mblox/mblox_test.go +++ b/handlers/mblox/mblox_test.go @@ -137,7 +137,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedMsgStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to parse response body from MBlox", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("", "", "unable to parse response body from MBlox")}, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", diff --git a/handlers/mtarget/mtarget_test.go b/handlers/mtarget/mtarget_test.go index 119c13beb..045531dd8 100644 --- a/handlers/mtarget/mtarget_test.go +++ b/handlers/mtarget/mtarget_test.go @@ -118,7 +118,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"results":[{"code": "3", "ticket": "null"}]}`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("Error status code, failing permanently", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("", "", "Error status code, failing permanently")}, SendPrep: setSendURL, }, } diff --git a/handlers/nexmo/nexmo.go b/handlers/nexmo/nexmo.go index fed9bfe2a..be167a414 100644 --- a/handlers/nexmo/nexmo.go +++ b/handlers/nexmo/nexmo.go @@ -134,7 +134,7 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } if form.ErrCode != 0 { - clog.Error(courier.ErrorServiceSpecific("vonage", "d"+strconv.Itoa(form.ErrCode), dlrErrorCodes[form.ErrCode])) + clog.Error(courier.ErrorExternal("dlr:"+strconv.Itoa(form.ErrCode), dlrErrorCodes[form.ErrCode])) } status := h.Backend().NewMsgStatusForExternalID(channel, form.MessageID, msgStatus, clog) @@ -235,7 +235,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann errCode, _ := strconv.Atoi(nexmoStatus) if err != nil || nexmoStatus != "0" { // https://developer.vonage.com/messaging/sms/guides/troubleshooting-sms - clog.Error(courier.ErrorServiceSpecific("vonage", "s"+nexmoStatus, sendErrorCodes[errCode])) + clog.Error(courier.ErrorExternal("send:"+nexmoStatus, sendErrorCodes[errCode])) return status, nil } diff --git a/handlers/nexmo/nexmo_test.go b/handlers/nexmo/nexmo_test.go index 445bca387..6bffde3a4 100644 --- a/handlers/nexmo/nexmo_test.go +++ b/handlers/nexmo/nexmo_test.go @@ -77,7 +77,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedBodyContains: `"status":"F"`, ExpectedMsgStatus: courier.MsgFailed, ExpectedExternalID: "external1", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("vonage", "d6", "Anti-Spam Rejection")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("dlr:6", "Anti-Spam Rejection")}, }, { Label: "Status accepted", @@ -170,7 +170,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Error status", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("vonage", "s10", "Too Many Existing Binds")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("send:10", "Too Many Existing Binds")}, SendPrep: setSendURL, }, { @@ -201,7 +201,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedPostParams: map[string]string{"text": "Simple Message", "to": "250788383383", "from": "2020", "api_key": "nexmo-api-key", "api_secret": "nexmo-api-secret", "status-report-req": "1", "type": "text"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("vonage", "s1", "Throttled")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("send:1", "Throttled")}, SendPrep: setSendURL, }, } diff --git a/handlers/novo/novo_test.go b/handlers/novo/novo_test.go index b420a313d..ab516548f 100644 --- a/handlers/novo/novo_test.go +++ b/handlers/novo/novo_test.go @@ -100,7 +100,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"error": "Incorrect Query String Authentication ","expectedQueryString": "8868;18686846480;test;"}`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received invalid response", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("", "", "received invalid response")}, SendPrep: setSendURL, }, { @@ -110,7 +110,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{"error": "Incorrect Query String Authentication ","expectedQueryString": "8868;18686846480;test;"}`, MockResponseStatus: 200, ExpectedMsgStatus: "F", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received invalid response", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("", "", "received invalid response")}, SendPrep: setSendURL, }, } diff --git a/handlers/plivo/plivo_test.go b/handlers/plivo/plivo_test.go index bdbc5ae28..5d00c3515 100644 --- a/handlers/plivo/plivo_test.go +++ b/handlers/plivo/plivo_test.go @@ -105,7 +105,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedMsgStatus: "E", MockResponseBody: `{ "missing":"OzYDlvf3SQVc" }`, MockResponseStatus: 200, - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to parse response body from Plivo", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("", "", "unable to parse response body from Plivo")}, ExpectedHeaders: map[string]string{ "Content-Type": "application/json", "Accept": "application/json", diff --git a/handlers/slack/slack_test.go b/handlers/slack/slack_test.go index 2c899e64a..1027d6e25 100644 --- a/handlers/slack/slack_test.go +++ b/handlers/slack/slack_test.go @@ -206,7 +206,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 200, ExpectedRequestBody: `{"channel":"U0123ABCDEF","text":"Hello"}`, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("invalid_auth", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("", "", "invalid_auth")}, SendPrep: setSendUrl, }, } diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index ae79ae067..11c83a398 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -312,7 +312,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann hasError = err != nil default: - clog.Error(courier.ErrorUnsupportedMedia(attachment.ContentType)) + clog.Error(courier.ErrorMediaUnsupported(attachment.ContentType)) hasError = true } } diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index d566557a7..e41dd2311 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -846,7 +846,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgURN: "telegram:12345", MsgAttachments: []string{"unknown/foo:https://foo.bar/unknown.foo"}, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.ErrorUnsupportedMedia("unknown/foo")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorMediaUnsupported("unknown/foo")}, SendPrep: setSendURL, }, } diff --git a/handlers/test.go b/handlers/test.go index 9af8e3f95..90ce69431 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -354,7 +354,7 @@ func RunChannelSendTestCases(t *testing.T, channel courier.Channel, handler cour // sender adds returned error to channel log if there aren't other logged errors if err != nil && len(clog.Errors()) == 0 { - clog.Error(courier.NewChannelError(err.Error(), "")) + clog.RawError(err) } assert.Equal(t, tc.ExpectedErrors, clog.Errors(), "unexpected errors logged") diff --git a/handlers/twiml/twiml.go b/handlers/twiml/twiml.go index b91b6009f..4482f18cf 100644 --- a/handlers/twiml/twiml.go +++ b/handlers/twiml/twiml.go @@ -452,5 +452,5 @@ func (h *handler) WriteRequestIgnored(ctx context.Context, w http.ResponseWriter func twilioError(code int64) *courier.ChannelError { codeAsStr := strconv.Itoa(int(code)) errMsg, _ := jsonparser.GetString(errorCodes, codeAsStr) - return courier.ErrorServiceSpecific("twilio", codeAsStr, errMsg) + return courier.ErrorExternal(codeAsStr, errMsg) } diff --git a/handlers/twiml/twiml_test.go b/handlers/twiml/twiml_test.go index 1137c2c63..bdeb44a43 100644 --- a/handlers/twiml/twiml_test.go +++ b/handlers/twiml/twiml_test.go @@ -107,7 +107,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "Attempt to send to unsubscribed recipient")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("21610", "Attempt to send to unsubscribed recipient")}, PrepRequest: addValidSignature, }, {Label: "Status No Params", URL: statusURL, Data: " ", ExpectedRespStatus: 200, ExpectedBodyContains: "no msg status, ignoring", @@ -154,7 +154,7 @@ var tmsTestCases = []ChannelHandleTestCase{ ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "Attempt to send to unsubscribed recipient")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("21610", "Attempt to send to unsubscribed recipient")}, PrepRequest: addValidSignature, }, {Label: "Status TMS extra", URL: tmsStatusURL, Data: tmsStatusExtra, ExpectedRespStatus: 200, ExpectedBodyContains: `"status":"S"`, ExpectedMsgStatus: courier.MsgSent, @@ -203,7 +203,7 @@ var twTestCases = []ChannelHandleTestCase{ ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "Attempt to send to unsubscribed recipient")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("21610", "Attempt to send to unsubscribed recipient")}, PrepRequest: addValidSignature, }, {Label: "Status No Params", URL: twStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedBodyContains: "no msg status, ignoring", @@ -237,7 +237,7 @@ var swTestCases = []ChannelHandleTestCase{ ExpectedMsgStatus: courier.MsgFailed, ExpectedEvent: "stop_contact", ExpectedURN: "tel:+12028831111", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "Attempt to send to unsubscribed recipient")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("21610", "Attempt to send to unsubscribed recipient")}, PrepRequest: addValidSignature, }, {Label: "Status No Params", URL: swStatusURL, Data: " ", ExpectedRespStatus: 200, ExpectedBodyContains: "no msg status, ignoring"}, @@ -390,7 +390,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/t/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedStopEvent: true, ExpectedMsgStatus: "F", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "Attempt to send to unsubscribed recipient")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("21610", "Attempt to send to unsubscribed recipient")}, SendPrep: setSendURL, }, { @@ -497,7 +497,7 @@ var tmsDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "MessagingServiceSid": "messageServiceSID", "StatusCallback": "https://localhost/c/tms/8eb23e93-5ecb-45ba-b726-3b064e0c56cd/status?id=10&action=callback"}, ExpectedStopEvent: true, ExpectedMsgStatus: "F", - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "Attempt to send to unsubscribed recipient")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("21610", "Attempt to send to unsubscribed recipient")}, SendPrep: setSendURL, }, { @@ -582,7 +582,7 @@ var twDefaultSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/tw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "F", ExpectedStopEvent: true, - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "Attempt to send to unsubscribed recipient")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("21610", "Attempt to send to unsubscribed recipient")}, SendPrep: setSendURL, }, { @@ -667,7 +667,7 @@ var swSendTestCases = []ChannelSendTestCase{ ExpectedPostParams: map[string]string{"Body": "Stopped Contact", "To": "+250788383383", "From": "2020", "StatusCallback": "https://localhost/c/sw/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&action=callback"}, ExpectedMsgStatus: "F", ExpectedStopEvent: true, - ExpectedErrors: []*courier.ChannelError{courier.ErrorServiceSpecific("twilio", "21610", "Attempt to send to unsubscribed recipient")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("21610", "Attempt to send to unsubscribed recipient")}, SendPrep: setSendURL, }, { diff --git a/handlers/twitter/twitter_test.go b/handlers/twitter/twitter_test.go index 89b6057bb..b9c20f780 100644 --- a/handlers/twitter/twitter_test.go +++ b/handlers/twitter/twitter_test.go @@ -346,7 +346,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, ExpectedMsgStatus: "W", ExpectedExternalID: "133", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to upload media, unsupported Twitter attachment", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("", "", "unable to upload media, unsupported Twitter attachment")}, SendPrep: setSendURL, }, { @@ -356,7 +356,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 200, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("unable to get message_id from body", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("", "", "unable to get message_id from body")}, SendPrep: setSendURL, }, { diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index 515be0b8f..20b41d2fe 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -375,7 +375,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann msgText = "" default: - clog.Error(courier.ErrorUnsupportedMedia(mediaType)) + clog.Error(courier.ErrorMediaUnsupported(mediaType)) } } else { diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index 2c214ceb5..ca8b9a010 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -146,7 +146,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received non-0 status: '3'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("", "", "received non-0 status: '3'")}, SendPrep: setSendURL, }, { @@ -177,7 +177,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ var invalidTokenSendTestCases = []ChannelSendTestCase{ { Label: "Invalid token", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("missing auth token in config", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("", "", "missing auth token in config")}, }, } diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index f2212dcb2..5ddac8dbc 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -651,7 +651,7 @@ func buildPayloads(msg courier.Msg, h *handler, clog *courier.ChannelLog) ([]int payload.Video = mediaPayload payloads = append(payloads, payload) } else { - clog.Error(courier.ErrorUnsupportedMedia(mimeType)) + clog.Error(courier.ErrorMediaUnsupported(mimeType)) break } } diff --git a/handlers/whatsapp/whatsapp_test.go b/handlers/whatsapp/whatsapp_test.go index b2b5c7bdc..87831f893 100644 --- a/handlers/whatsapp/whatsapp_test.go +++ b/handlers/whatsapp/whatsapp_test.go @@ -754,7 +754,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ Label: "Template Invalid Language", MsgText: "templated message", MsgURN: "whatsapp:250788123123", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError(`unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`, "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("", "", `unable to decode template: {"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}} for channel: 8eb23e93-5ecb-45ba-b726-3b064e0c56ab: unable to find mapping for language: bnt`)}, MsgMetadata: json.RawMessage(`{"templating": { "template": { "name": "revive_issue", "uuid": "8ca114b4-bee2-4d3b-aaf1-9aa6b48d41e8" }, "language": "bnt", "variables": ["Chef", "tomorrow"]}}`), }, { diff --git a/handlers/zenviaold/zenviaold_test.go b/handlers/zenviaold/zenviaold_test.go index d58d42d78..0cd62fed1 100644 --- a/handlers/zenviaold/zenviaold_test.go +++ b/handlers/zenviaold/zenviaold_test.go @@ -199,7 +199,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ }, ExpectedRequestBody: `{"sendSmsRequest":{"to":"250788383383","schedule":"","msg":"No External ID","callbackOption":"FINAL","id":"10","aggregateId":""}}`, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("received non-success response: '05'", "")}, + ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("", "", "received non-success response: '05'")}, SendPrep: setSendURL}, { Label: "Error Sending", diff --git a/sender.go b/sender.go index 649450b62..dd7316d38 100644 --- a/sender.go +++ b/sender.go @@ -217,7 +217,7 @@ func (w *Sender) sendMessage(msg Msg) { // handlers should log errors implicitly with user friendly messages.. but if not.. add what we have if len(clog.Errors()) == 0 { - clog.Error(NewChannelError(err.Error(), "")) + clog.RawError(err) } // possible for handlers to only return an error in which case we construct an error status diff --git a/test/handler.go b/test/handler.go index 77090044f..c345c0aaf 100644 --- a/test/handler.go +++ b/test/handler.go @@ -51,7 +51,7 @@ func (h *mockHandler) Send(ctx context.Context, msg courier.Msg, clog *courier.C clog.HTTP(trace) // log an error than contains a value that should be redacted - clog.Error(courier.NewChannelError("contains sesame seeds", "")) + clog.Error(courier.NewChannelError("seeds", "", "contains sesame seeds")) return h.backend.NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgSent, clog), nil } From ee635ce44f6c39a26bdfe91b7094b217686db0a9 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 21 Nov 2022 13:13:50 -0500 Subject: [PATCH 279/294] Update CHANGELOG.md for v7.5.62 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93f6be002..4bd89fc01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.62 (2022-11-21) +------------------------- + * Rework channel log errors to have separate code and ext_code fields to remove the need for namespaces + * Add logs for WhatsApp Cloud specific errors + v7.5.61 (2022-11-18) ------------------------- * Ensure that URN and contact name are valid utf8 before trying to write to DB From b79ed630189cca21e4fd2fda6616de0802092ae6 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Tue, 22 Nov 2022 17:17:22 +0200 Subject: [PATCH 280/294] Record Facebook and Instagram external code error --- handlers/facebookapp/facebookapp.go | 30 +++++++++++++---- handlers/facebookapp/facebookapp_test.go | 42 ++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 77b109659..84e40c31e 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -844,6 +844,15 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("unssuported channel type") } +type fbaMTResponse struct { + ExternalID string `json:"message_id"` + RecipientID string `json:"recipient_id"` + Error struct { + Message string `json:"message"` + Code int `json:"code"` + } `json:"error"` +} + func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { // can't do anything without an access token accessToken := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") @@ -925,23 +934,30 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, clog) - if err != nil || resp.StatusCode/100 != 2 { + _, respBody, _ := handlers.RequestHTTP(req, clog) + respPayload := &fbaMTResponse{} + err = json.Unmarshal(respBody, respPayload) + if err != nil { + clog.Error(courier.ErrorResponseUnparseable("JSON")) return status, nil } - externalID, err := jsonparser.GetString(respBody, "message_id") - if err != nil { + if respPayload.Error.Code != 0 { + clog.Error(courier.ErrorExternal(strconv.Itoa(respPayload.Error.Code), respPayload.Error.Message)) + return status, nil + } + + if respPayload.ExternalID == "" { clog.Error(courier.ErrorResponseValueMissing("message_id")) return status, nil } // if this is our first message, record the external id if i == 0 { - status.SetExternalID(externalID) + status.SetExternalID(respPayload.ExternalID) if msg.URN().IsFacebookRef() { - recipientID, err := jsonparser.GetString(respBody, "recipient_id") - if err != nil { + recipientID := respPayload.RecipientID + if recipientID == "" { clog.Error(courier.ErrorResponseValueMissing("recipient_id")) return status, nil } diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 7044148f5..94051fbad 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -1043,6 +1043,27 @@ var SendTestCasesFBA = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 403, ExpectedMsgStatus: "E", + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("message_id")}, + SendPrep: setSendURL, + }, + { + Label: "Error Bad JSON", + MsgText: "Error", + MsgURN: "facebook:12345", + MockResponseBody: `bad json`, + MockResponseStatus: 403, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseUnparseable("JSON")}, + ExpectedMsgStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error external", + MsgText: "Error", + MsgURN: "facebook:12345", + MockResponseBody: `{ "error": {"message": "The image size is too large.","code": 36000 }}`, + MockResponseStatus: 403, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("36000", "The image size is too large.")}, + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } @@ -1156,6 +1177,27 @@ var SendTestCasesIG = []ChannelSendTestCase{ MockResponseBody: `{ "is_error": true }`, MockResponseStatus: 403, ExpectedMsgStatus: "E", + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("message_id")}, + SendPrep: setSendURL, + }, + { + Label: "Error Bad JSON", + MsgText: "Error", + MsgURN: "instagram:12345", + MockResponseBody: `bad json`, + MockResponseStatus: 403, + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseUnparseable("JSON")}, + ExpectedMsgStatus: "E", + SendPrep: setSendURL, + }, + { + Label: "Error external", + MsgText: "Error", + MsgURN: "instagram:12345", + MockResponseBody: `{ "error": {"message": "The image size is too large.","code": 36000 }}`, + MockResponseStatus: 403, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("36000", "The image size is too large.")}, + ExpectedMsgStatus: "E", SendPrep: setSendURL, }, } From 8e4aef7a48ccdda917d60eb56cda4798de2b9377 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Thu, 24 Nov 2022 16:47:41 +0200 Subject: [PATCH 281/294] Add support for external telegram errors --- handlers/telegram/telegram.go | 34 +++++++---- handlers/telegram/telegram_test.go | 92 +++++++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 14 deletions(-) diff --git a/handlers/telegram/telegram.go b/handlers/telegram/telegram.go index 11c83a398..a521177c5 100644 --- a/handlers/telegram/telegram.go +++ b/handlers/telegram/telegram.go @@ -10,7 +10,6 @@ import ( "strings" "time" - "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/utils" @@ -170,6 +169,7 @@ func (h *handler) sendMsgPart(msg courier.Msg, token string, path string, form u err = json.Unmarshal(respBody, response) if err != nil || resp.StatusCode/100 != 2 || !response.Ok { + clog.Error(courier.ErrorExternal(strconv.Itoa(response.ErrorCode), response.Description)) if response.ErrorCode == 403 && response.Description == "Forbidden: bot was blocked by the user" { return "", true, errors.Errorf("response not 'ok'") } @@ -324,6 +324,15 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return status, nil } +type fileResponse struct { + Ok bool `json:"ok"` + ErrorCode int `json:"error_code"` + Description string `json:"description"` + Result struct { + FilePath string `json:"file_path"` + } `json:"result"` +} + func (h *handler) resolveFileID(ctx context.Context, channel courier.Channel, fileID string, clog *courier.ChannelLog) (string, error) { confAuth := channel.ConfigForKey(courier.ConfigAuthToken, "") authToken, isStr := confAuth.(string) @@ -343,27 +352,28 @@ func (h *handler) resolveFileID(ctx context.Context, channel courier.Channel, fi courier.LogRequestError(req, channel, err) } - resp, respBody, err := handlers.RequestHTTP(req, clog) - if err != nil || resp.StatusCode/100 != 2 { + resp, respBody, _ := handlers.RequestHTTP(req, clog) + + respPayload := &fileResponse{} + err = json.Unmarshal(respBody, respPayload) + if err != nil { + clog.Error(courier.ErrorResponseUnparseable("JSON")) return "", errors.New("unable to resolve file") } - // was this request successful? - ok, err := jsonparser.GetBoolean(respBody, "ok") - if err != nil { - return "", errors.Errorf("no 'ok' in response") + if resp.StatusCode/100 != 2 || respPayload.ErrorCode != 0 { + clog.Error(courier.ErrorExternal(strconv.Itoa(respPayload.ErrorCode), respPayload.Description)) + return "", errors.New("unable to resolve file") } - if !ok { + if !respPayload.Ok { return "", errors.Errorf("file id '%s' not present", fileID) } - // grab the path for our file - filePath, err := jsonparser.GetString(respBody, "result", "file_path") - if err != nil { + filePath := respPayload.Result.FilePath + if filePath == "" { return "", errors.Errorf("no 'result.file_path' in response") } - // return the URL return fmt.Sprintf("%s/file/bot%s/%s", apiURL, authToken, filePath), nil } diff --git a/handlers/telegram/telegram_test.go b/handlers/telegram/telegram_test.go index e41dd2311..bc2b4df66 100644 --- a/handlers/telegram/telegram_test.go +++ b/handlers/telegram/telegram_test.go @@ -191,6 +191,70 @@ var noOkFile = ` } }` +var invalidJsonFile = ` +{ + "update_id":174114373, + "message":{ + "message_id":44, + "from":{ + "id":3527065, + "first_name":"Nic", + "last_name":"Pottier" + }, + "chat":{ + "id":3527065, + "first_name":"Nic", + "last_name":"Pottier", + "type":"private" + }, + "date":1454119668, + "sticker":{ + "width":436, + "height":512, + "thumb":{ + "file_id":"invalidjson", + "file_size":2510, + "width":77, + "height":90 + }, + "file_id":"BQADAwADRQADyIsGAAHtBskMy6GoLAI", + "file_size":38440 + } + } +}` + +var errorFile = ` +{ + "update_id":174114373, + "message":{ + "message_id":44, + "from":{ + "id":3527065, + "first_name":"Nic", + "last_name":"Pottier" + }, + "chat":{ + "id":3527065, + "first_name":"Nic", + "last_name":"Pottier", + "type":"private" + }, + "date":1454119668, + "sticker":{ + "width":436, + "height":512, + "thumb":{ + "file_id":"error", + "file_size":2510, + "width":77, + "height":90 + }, + "file_id":"BQADAwADRQADyIsGAAHtBskMy6GoLAI", + "file_size":38440 + } + } +}` + var noFile = ` { "update_id":174114373, @@ -613,7 +677,23 @@ var testCases = []ChannelHandleTestCase{ URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", Data: noOkFile, ExpectedRespStatus: 200, - ExpectedBodyContains: "no 'ok' in response", + ExpectedBodyContains: "not present", + }, + { + Label: "Receive invalid JSON File response", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: invalidJsonFile, + ExpectedRespStatus: 200, + ExpectedBodyContains: "unable to resolve file", + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseUnparseable("JSON")}, + }, + { + Label: "Receive error File response", + URL: "/c/tg/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive/", + Data: errorFile, + ExpectedRespStatus: 200, + ExpectedBodyContains: "unable to resolve file", + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseUnparseable("JSON")}, }, { Label: "Receive NotOk FileID", @@ -652,6 +732,12 @@ func buildMockTelegramService(testCases []ChannelHandleTestCase) *httptest.Serve case "notok": w.Write([]byte(`{ "ok": false, "result": { "file_path": "nothing" } }`)) return + case "invalidjson": + w.Write([]byte(`invalid`)) + return + case "error": + w.Write([]byte(`{ "error_code": 500, "description": "error loading file" }`)) + return case "nook": w.Write([]byte(`{}`)) return @@ -765,9 +851,10 @@ var defaultSendTestCases = []ChannelSendTestCase{ Label: "Error", MsgText: "Error", MsgURN: "telegram:12345", - MockResponseBody: `{ "ok": false }`, + MockResponseBody: `{ "ok": false, "error_code":400, "description":"Bot domain invalid." }`, MockResponseStatus: 403, ExpectedPostParams: map[string]string{"text": `Error`, "chat_id": "12345"}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("400", "Bot domain invalid.")}, ExpectedMsgStatus: "E", SendPrep: setSendURL, }, @@ -779,6 +866,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ MockResponseStatus: 403, ExpectedPostParams: map[string]string{"text": `Stopped Contact`, "chat_id": "12345"}, ExpectedMsgStatus: "F", + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("403", "Forbidden: bot was blocked by the user")}, ExpectedStopEvent: true, SendPrep: setSendURL, }, From 409a2dfe500a912d304cd9187cea07b9a6f504b9 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Fri, 25 Nov 2022 16:22:59 +0200 Subject: [PATCH 282/294] Add support for Viber channel type external errors --- handlers/viber/viber.go | 16 ++++++++++++---- handlers/viber/viber_test.go | 5 +++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index 20b41d2fe..b56e094d2 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -13,7 +13,6 @@ import ( "strconv" "strings" - "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/gocommon/urns" @@ -308,6 +307,11 @@ type mtPayload struct { Keyboard *Keyboard `json:"keyboard,omitempty"` } +type mtResponse struct { + Status int `json:"status"` + StatusMessage string `json:"status_message"` +} + // Send sends the given message, logging any HTTP calls or errors func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { authToken := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") @@ -413,15 +417,19 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { + clog.Error(courier.ErrorResponseStatusCode()) return status, nil } - responseStatus, err := jsonparser.GetInt(respBody, "status") + + respPayload := &mtResponse{} + err = json.Unmarshal(respBody, respPayload) if err != nil { clog.Error(courier.ErrorResponseUnparseable("JSON")) return status, nil } - if responseStatus != 0 { - clog.RawError(errors.Errorf("received non-0 status: '%d'", responseStatus)) + + if respPayload.Status != 0 { + clog.Error(courier.ErrorExternal(strconv.Itoa(respPayload.Status), respPayload.StatusMessage)) return status, nil } diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index ca8b9a010..39736a782 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -142,11 +142,11 @@ var defaultSendTestCases = []ChannelSendTestCase{ MsgText: "Simple Message", MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", MockResponseStatus: 200, - MockResponseBody: `{"status":3,"status_message":"InvalidToken"}`, + MockResponseBody: `{"status":3,"status_message":"badData"}`, ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.NewChannelError("", "", "received non-0 status: '3'")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("3", "badData")}, SendPrep: setSendURL, }, { @@ -170,6 +170,7 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Error Message","type":"text","tracking_data":"10"}`, ExpectedMsgStatus: "E", + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseStatusCode()}, SendPrep: setSendURL, }, } From ff8aeee4e5d1ab58356c880f73a390906979834f Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Tue, 29 Nov 2022 15:20:42 +0200 Subject: [PATCH 283/294] Use error descriptions for Viber --- handlers/viber/viber.go | 34 +++++++++++++++++++++++++++++++++- handlers/viber/viber_test.go | 14 +++++++++++++- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/handlers/viber/viber.go b/handlers/viber/viber.go index b56e094d2..938816dd5 100644 --- a/handlers/viber/viber.go +++ b/handlers/viber/viber.go @@ -28,6 +28,34 @@ var ( sendURL = "https://chatapi.viber.com/pa/send_message" maxMsgLength = 7000 descriptionMaxLength = 512 + + // https://developers.viber.com/docs/api/rest-bot-api/#error-codes + sendErrorCodes = map[int]string{ + 1: "The webhook URL is not valid", + 2: "The authentication token is not valid", + 3: "There is an error in the request itself (missing comma, brackets, etc.)", + 4: "Some mandatory data is missing", + 5: "The receiver is not registered to Viber", + 6: "The receiver is not subscribed to the account", + 7: "The account is blocked", + 8: "The account associated with the token is not a account.", + 9: "The account is suspended", + 10: "No webhook was set for the account", + 11: "The receiver is using a device or a Viber version that don’t support accounts", + 12: "Rate control breach", + 13: "Maximum supported account version by all user’s devices is less than the minApiVersion in the message", + 14: "minApiVersion is not compatible to the message fields", + 15: "The account is not authorized", + 16: "Inline message not allowed", + 17: "The account is not inline", + 18: "Failed to post to public account. The bot is missing a Public Chat interface", + 19: "Cannot send broadcast message", + 20: "Attempt to send broadcast message from the bot", + 21: "The message sent is not supported in the destination country", + 22: "The bot does not support payment messages", + 23: "The non-billable bot has reached the monthly threshold of free out of session messages", + 24: "No balance for a billable bot (when the “free out of session messages” threshold has been reached)", + } ) func init() { @@ -429,7 +457,11 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } if respPayload.Status != 0 { - clog.Error(courier.ErrorExternal(strconv.Itoa(respPayload.Status), respPayload.StatusMessage)) + errorMessage, found := sendErrorCodes[respPayload.Status] + if !found { + errorMessage = "General error" + } + clog.Error(courier.ErrorExternal(strconv.Itoa(respPayload.Status), errorMessage)) return status, nil } diff --git a/handlers/viber/viber_test.go b/handlers/viber/viber_test.go index 39736a782..b33715d25 100644 --- a/handlers/viber/viber_test.go +++ b/handlers/viber/viber_test.go @@ -146,7 +146,19 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, ExpectedMsgStatus: "E", - ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("3", "badData")}, + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("3", "There is an error in the request itself (missing comma, brackets, etc.)")}, + SendPrep: setSendURL, + }, + { + Label: "Got general error response", + MsgText: "Simple Message", + MsgURN: "viber:xy5/5y6O81+/kbWHpLhBoA==", + MockResponseStatus: 200, + MockResponseBody: `{"status":99,"status_message":"General error"}`, + ExpectedHeaders: map[string]string{"Content-Type": "application/json", "Accept": "application/json"}, + ExpectedRequestBody: `{"auth_token":"Token","receiver":"xy5/5y6O81+/kbWHpLhBoA==","text":"Simple Message","type":"text","tracking_data":"10"}`, + ExpectedMsgStatus: "E", + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("99", "General error")}, SendPrep: setSendURL, }, { From 405349de3c9c81627eb0b2ae4be56e42eb62c881 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 29 Nov 2022 09:09:14 -0500 Subject: [PATCH 284/294] Update deps --- go.mod | 12 ++++++------ go.sum | 42 +++++++++++++++++++++++++++++++----------- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index e208bdc19..4787774d7 100644 --- a/go.mod +++ b/go.mod @@ -4,18 +4,18 @@ go 1.19 require ( github.com/antchfx/xmlquery v1.3.12 - github.com/aws/aws-sdk-go v1.44.124 + github.com/aws/aws-sdk-go v1.44.146 github.com/buger/jsonparser v1.1.1 github.com/dghubble/oauth1 v0.7.1 github.com/evalphobia/logrus_sentry v0.8.2 github.com/go-chi/chi v4.1.2+incompatible - github.com/gofrs/uuid v4.3.0+incompatible + github.com/gofrs/uuid v4.3.1+incompatible github.com/gomodule/redigo v1.8.9 github.com/gorilla/schema v1.2.0 github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.7 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.33.0 + github.com/nyaruka/gocommon v1.33.1 github.com/nyaruka/null v1.2.0 github.com/nyaruka/redisx v0.2.2 github.com/patrickmn/go-cache v2.1.0+incompatible @@ -45,11 +45,11 @@ require ( github.com/naoina/go-stringutil v0.1.0 // indirect github.com/naoina/toml v0.1.1 // indirect github.com/nyaruka/librato v1.0.0 // indirect - github.com/nyaruka/phonenumbers v1.1.2 // indirect + github.com/nyaruka/phonenumbers v1.1.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect - golang.org/x/net v0.1.0 // indirect - golang.org/x/sys v0.1.0 // indirect + golang.org/x/net v0.2.0 // indirect + golang.org/x/sys v0.2.0 // indirect golang.org/x/text v0.4.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/go.sum b/go.sum index c9ff8a604..eb92d3f70 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/antchfx/xmlquery v1.3.12 h1:6TMGpdjpO/P8VhjnaYPXuqT3qyJ/VsqoyNTmJzNBT github.com/antchfx/xmlquery v1.3.12/go.mod h1:3w2RvQvTz+DaT5fSgsELkSJcdNgkmg6vuXDEuhdwsPQ= github.com/antchfx/xpath v1.2.1 h1:qhp4EW6aCOVr5XIkT+l6LJ9ck/JsUH/yyauNgTQkBF8= github.com/antchfx/xpath v1.2.1/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= -github.com/aws/aws-sdk-go v1.44.124 h1:Xe1WQRUUekZf6ZFm3SD0vplB/AP/hymVqMiRS9LQRIs= -github.com/aws/aws-sdk-go v1.44.124/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.146 h1:7YdGgPxDPRJu/yYffzZp/H7yHzQ6AqmuNFZPYraaN8I= +github.com/aws/aws-sdk-go v1.44.146/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s= @@ -31,12 +31,11 @@ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/j github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= -github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= +github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -76,14 +75,14 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.33.0 h1:X68AFxyPZHokumiGwAq0CqkU3/j7ZzGrjxTu9azH2ko= -github.com/nyaruka/gocommon v1.33.0/go.mod h1:k03R7UY1IX65qPEncv7MgvQx7BZ2laR+ikN1GQjTMbY= +github.com/nyaruka/gocommon v1.33.1 h1:RUy1O5Ly4tAaQDDpahds8z+4uewwsXg6SNCH0hYm7pE= +github.com/nyaruka/gocommon v1.33.1/go.mod h1:gusIA2aNC8EPB3ozlP4O0PaBiHUNq5+f1peRNvcn0DI= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= github.com/nyaruka/null v1.2.0/go.mod h1:HSAFbLNOaEhHnoU0VCveCPz0GDtJ3GEtFWhvnBNkhPE= -github.com/nyaruka/phonenumbers v1.1.2 h1:MIDljnA08HCUzgNOrkCYja7CJ5U9ylZ+U3Sge8RWW14= -github.com/nyaruka/phonenumbers v1.1.2/go.mod h1:cGaEsOrLjIL0iKGqJR5Rfywy86dSkbApEpXuM9KySNA= +github.com/nyaruka/phonenumbers v1.1.4 h1:de8exybd7+g9q+gXP04Ypt9ijFYXXm8wrgqPf+Ckk20= +github.com/nyaruka/phonenumbers v1.1.4/go.mod h1:yShPJHDSH3aTKzCbXyVxNpbl2kA+F+Ne5Pun/MvFRos= github.com/nyaruka/redisx v0.2.2 h1:OAJ4g1So2opn6O5akDWEWiDWgEOvPMKU10EUCG/Nv9Y= github.com/nyaruka/redisx v0.2.2/go.mod h1:cdbAm4y/+oFWu7qFzH2ERPeqRXJC2CtgRhwcBacM4Oc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= @@ -113,25 +112,46 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= From 2ca8875748f234f423328b45ea6ba9f7bb4bfa17 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 29 Nov 2022 09:09:25 -0500 Subject: [PATCH 285/294] Remove un-needed codecov config --- codecov.yml | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 codecov.yml diff --git a/codecov.yml b/codecov.yml deleted file mode 100644 index eb6268bf3..000000000 --- a/codecov.yml +++ /dev/null @@ -1,3 +0,0 @@ -ignore: - - "vendor/.*" - - "**/*test.go" \ No newline at end of file From b7d23fc64b083274dd33d1a47b85467beff2a8b3 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Tue, 29 Nov 2022 16:31:06 +0200 Subject: [PATCH 286/294] Add logs for Line specific errors --- handlers/line/line.go | 33 +++++++++++++++++++++++++++------ handlers/line/line_test.go | 14 +++++++++++++- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/handlers/line/line.go b/handlers/line/line.go index 91735469f..35779ee5e 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -11,9 +11,9 @@ import ( "io" "net/http" "net/url" + "strconv" "time" - "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/utils" @@ -289,6 +289,10 @@ type mtPayload struct { Messages json.RawMessage `json:"messages"` } +type mtResponse struct { + Message string `json:"message"` +} + // Send sends the given message, logging any HTTP calls or errors func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { authToken := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") @@ -368,25 +372,42 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann } resp, respBody, err := handlers.RequestHTTP(req, clog) + if err == nil && resp.StatusCode/100 == 2 { batch = []string{} batchCount = 0 continue } - // retry without the reply token if it's invalid - errMsg, err := jsonparser.GetString(respBody, "message") - if err == nil && errMsg == "Invalid reply token" { + respPayload := &mtResponse{} + err = json.Unmarshal(respBody, respPayload) + if err != nil { + clog.Error(courier.ErrorResponseUnparseable("JSON")) + return status, nil + } + + errMsg := respPayload.Message + if errMsg == "Invalid reply token" { req, err = buildSendMsgRequest(authToken, msg.URN().Path(), "", batch) if err != nil { return status, err } - resp, _, err := handlers.RequestHTTP(req, clog) - if err != nil || resp.StatusCode/100 != 2 { + resp, respBody, _ := handlers.RequestHTTP(req, clog) + + respPayload := &mtResponse{} + err = json.Unmarshal(respBody, respPayload) + if err != nil { + clog.Error(courier.ErrorResponseUnparseable("JSON")) + return status, nil + } + + if resp.StatusCode/100 != 2 { + clog.Error(courier.ErrorExternal(strconv.Itoa(resp.StatusCode), respPayload.Message)) return status, nil } } else { + clog.Error(courier.ErrorExternal(strconv.Itoa(resp.StatusCode), respPayload.Message)) return status, err } } diff --git a/handlers/line/line_test.go b/handlers/line/line_test.go index 1eae62219..ca590b932 100644 --- a/handlers/line/line_test.go +++ b/handlers/line/line_test.go @@ -559,14 +559,26 @@ var defaultSendTestCases = []ChannelSendTestCase{ ExpectedMsgStatus: "W", SendPrep: setSendURL, }, + { + Label: "Invalid JSON response sending", + MsgText: "Error Sending", + MsgURN: "line:uabcdefghij", + MockResponseBody: ``, + MockResponseStatus: 403, + ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Error Sending"}]}`, + ExpectedMsgStatus: "E", + ExpectedErrors: []*courier.ChannelError{courier.ErrorResponseUnparseable("JSON")}, + SendPrep: setSendURL, + }, { Label: "Error Sending", MsgText: "Error Sending", MsgURN: "line:uabcdefghij", - MockResponseBody: `{"message": "Error"}`, + MockResponseBody: `{"message": "Failed to send messages"}`, MockResponseStatus: 403, ExpectedRequestBody: `{"to":"uabcdefghij","messages":[{"type":"text","text":"Error Sending"}]}`, ExpectedMsgStatus: "E", + ExpectedErrors: []*courier.ChannelError{courier.ErrorExternal("403", "Failed to send messages")}, SendPrep: setSendURL, }, } From cf705584592562d0069d794f5ce061a6dde85e7e Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 30 Nov 2022 17:13:22 -0500 Subject: [PATCH 287/294] Update CHANGELOG.md for v7.5.63 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bd89fc01..b96a40936 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.63 (2022-11-30) +------------------------- + * Add logs for Facebook, Instagram, Viber, Telgram and Line specific errors + * Update deps + v7.5.62 (2022-11-21) ------------------------- * Rework channel log errors to have separate code and ext_code fields to remove the need for namespaces From cd4153b4a1b35fe95fc64c6d969a30075a3ccaba Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 13 Dec 2022 18:11:41 -0500 Subject: [PATCH 288/294] Remove temp workaround to stop D360 channels taking longer than 5 seconds to request attachments --- attachments.go | 5 +---- handler.go | 1 - handlers/facebookapp/facebookapp.go | 4 ---- handlers/jiochat/jiochat.go | 5 ----- handlers/line/line.go | 5 ----- handlers/rocketchat/rocketchat.go | 5 ----- handlers/wechat/wechat.go | 5 ----- handlers/whatsapp/whatsapp.go | 12 ------------ 8 files changed, 1 insertion(+), 41 deletions(-) diff --git a/attachments.go b/attachments.go index 720bb023f..89eeb98a7 100644 --- a/attachments.go +++ b/attachments.go @@ -78,16 +78,13 @@ func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, at return nil, err } - var httpClient *http.Client var attRequest *http.Request handler := GetHandler(channel.ChannelType()) builder, isBuilder := handler.(AttachmentRequestBuilder) if isBuilder { - httpClient = builder.AttachmentRequestClient(channel) attRequest, err = builder.BuildAttachmentRequest(ctx, b, channel, parsedURL.String(), clog) } else { - httpClient = utils.GetHTTPClient() attRequest, err = http.NewRequest(http.MethodGet, attURL, nil) } @@ -95,7 +92,7 @@ func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, at return nil, errors.Wrap(err, "unable to create attachment request") } - trace, err := httpx.DoTrace(httpClient, attRequest, nil, nil, maxAttBodyReadBytes) + trace, err := httpx.DoTrace(utils.GetHTTPClient(), attRequest, nil, nil, maxAttBodyReadBytes) if trace != nil { clog.HTTP(trace) } diff --git a/handler.go b/handler.go index 522fbf6a4..732cb1d50 100644 --- a/handler.go +++ b/handler.go @@ -43,7 +43,6 @@ type URNDescriber interface { // AttachmentRequestBuilder is the interface handlers which can allow a custom way to download attachment media for messages should satisfy type AttachmentRequestBuilder interface { BuildAttachmentRequest(context.Context, Backend, Channel, string, *ChannelLog) (*http.Request, error) - AttachmentRequestClient(Channel) *http.Client } // RegisterHandler adds a new handler for a channel type, this is called by individual handlers when they are initialized diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 84e40c31e..d0b9ea0ae 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -1566,10 +1566,6 @@ func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, return req, nil } -func (*handler) AttachmentRequestClient(ch courier.Channel) *http.Client { - return utils.GetHTTPClient() -} - var _ courier.AttachmentRequestBuilder = (*handler)(nil) type TemplateMetadata struct { diff --git a/handlers/jiochat/jiochat.go b/handlers/jiochat/jiochat.go index 8dea6a47e..5ca3fd229 100644 --- a/handlers/jiochat/jiochat.go +++ b/handlers/jiochat/jiochat.go @@ -18,7 +18,6 @@ import ( "github.com/gomodule/redigo/redis" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/jsonx" "github.com/nyaruka/gocommon/urns" "github.com/pkg/errors" @@ -256,10 +255,6 @@ func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, return req, nil } -func (*handler) AttachmentRequestClient(ch courier.Channel) *http.Client { - return utils.GetHTTPClient() -} - var _ courier.AttachmentRequestBuilder = (*handler)(nil) func (h *handler) getAccessToken(ctx context.Context, channel courier.Channel, clog *courier.ChannelLog) (string, error) { diff --git a/handlers/line/line.go b/handlers/line/line.go index 35779ee5e..034d3a3c0 100644 --- a/handlers/line/line.go +++ b/handlers/line/line.go @@ -16,7 +16,6 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" "github.com/pkg/errors" ) @@ -195,10 +194,6 @@ func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, return req, nil } -func (*handler) AttachmentRequestClient(ch courier.Channel) *http.Client { - return utils.GetHTTPClient() -} - var _ courier.AttachmentRequestBuilder = (*handler)(nil) func (h *handler) validateSignature(channel courier.Channel, r *http.Request) error { diff --git a/handlers/rocketchat/rocketchat.go b/handlers/rocketchat/rocketchat.go index ad7c747b2..9e48dc4df 100644 --- a/handlers/rocketchat/rocketchat.go +++ b/handlers/rocketchat/rocketchat.go @@ -11,7 +11,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" ) @@ -103,10 +102,6 @@ func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, return req, nil } -func (*handler) AttachmentRequestClient(ch courier.Channel) *http.Client { - return utils.GetHTTPClient() -} - var _ courier.AttachmentRequestBuilder = (*handler)(nil) type mtPayload struct { diff --git a/handlers/wechat/wechat.go b/handlers/wechat/wechat.go index 44014c1c1..e01405639 100644 --- a/handlers/wechat/wechat.go +++ b/handlers/wechat/wechat.go @@ -18,7 +18,6 @@ import ( "github.com/gomodule/redigo/redis" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" "github.com/pkg/errors" ) @@ -276,10 +275,6 @@ func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, return req, nil } -func (*handler) AttachmentRequestClient(ch courier.Channel) *http.Client { - return utils.GetHTTPClient() -} - var _ courier.AttachmentRequestBuilder = (*handler)(nil) func (h *handler) getAccessToken(ctx context.Context, channel courier.Channel, clog *courier.ChannelLog) (string, error) { diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index 5ddac8dbc..238dfa9f6 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -44,8 +44,6 @@ var ( retryParam = "" failedMediaCache *cache.Cache - - d360AttachmentClient *http.Client ) func init() { @@ -54,9 +52,6 @@ func init() { courier.RegisterHandler(newWAHandler(courier.ChannelType(channelTypeTXW), "TextIt")) failedMediaCache = cache.New(15*time.Minute, 15*time.Minute) - - // seems that we get about 5 seconds to respond to Dialog360 so we can't spend long fetching attachments - d360AttachmentClient = &http.Client{Timeout: time.Second * 3} } type handler struct { @@ -332,13 +327,6 @@ func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, return req, nil } -func (*handler) AttachmentRequestClient(ch courier.Channel) *http.Client { - if ch.ChannelType() == channelTypeD3 { - return d360AttachmentClient - } - return utils.GetHTTPClient() -} - var _ courier.AttachmentRequestBuilder = (*handler)(nil) var waStatusMapping = map[string]courier.MsgStatusValue{ From 41529530b7bdbdf7f3d5ccb9794b9f44b6ad89ef Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 13 Dec 2022 18:22:37 -0500 Subject: [PATCH 289/294] Update CHANGELOG.md for v7.5.64 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b96a40936..693c6f17f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.64 (2022-12-13) +------------------------- + * Remove temp workaround to stop D360 channels taking longer than 5 seconds to request attachments + v7.5.63 (2022-11-30) ------------------------- * Add logs for Facebook, Instagram, Viber, Telgram and Line specific errors From 9b84a4d4343812605ac15f5818ce78dacbc7c0ea Mon Sep 17 00:00:00 2001 From: Robi9 Date: Mon, 9 Oct 2023 14:33:08 -0300 Subject: [PATCH 290/294] Fix dependencies for new version --- backends/rapidpro/msg.go | 10 +- config.go | 1 - go.mod | 17 +- go.sum | 13 +- handlers/facebookapp/facebookapp.go | 33 ++-- handlers/facebookapp/facebookapp_test.go | 5 +- handlers/slack/slack.go | 179 +++---------------- handlers/teams/teams.go | 38 ++-- handlers/teams/teams_test.go | 167 +++++++++--------- handlers/test.go | 43 +---- handlers/webhook.go | 14 +- handlers/weniwebchat/weniwebchat.go | 48 ++--- handlers/weniwebchat/weniwebchat_test.go | 203 ++++++++++----------- handlers/whatsapp/whatsapp.go | 216 +---------------------- server.go | 1 - test/msg.go | 2 + 16 files changed, 303 insertions(+), 687 deletions(-) diff --git a/backends/rapidpro/msg.go b/backends/rapidpro/msg.go index 12762d174..41c262b57 100644 --- a/backends/rapidpro/msg.go +++ b/backends/rapidpro/msg.go @@ -5,8 +5,12 @@ import ( "encoding/base64" "encoding/json" "fmt" + "log" + "os" + "strings" + "time" + "github.com/buger/jsonparser" - "github.com/gabriel-vasile/mimetype" "github.com/gomodule/redigo/redis" "github.com/lib/pq" "github.com/nyaruka/courier" @@ -16,10 +20,6 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" filetype "gopkg.in/h2non/filetype.v1" - "log" - "os" - "strings" - "time" ) // MsgDirection is the direction of a message diff --git a/config.go b/config.go index fc94c581a..cf5a1fa3e 100644 --- a/config.go +++ b/config.go @@ -25,7 +25,6 @@ type Config struct { S3DisableSSL bool `help:"whether we disable SSL when accessing S3. Should always be set to False unless you're hosting an S3 compatible service within a secure internal network"` S3ForcePathStyle bool `help:"whether we force S3 path style. Should generally need to default to False unless you're hosting an S3 compatible service"` - WhatsappAdminSystemUserToken string `help:"the token of the admin system user for WhatsApp"` WhatsappCloudApplicationSecret string `help:"the Whatsapp Cloud app secret"` WhatsappCloudWebhookSecret string `help:"the secret for WhatsApp Cloud webhook URL verification"` FacebookApplicationSecret string `help:"the Facebook app secret"` diff --git a/go.mod b/go.mod index adb69601e..a2c30eb8a 100644 --- a/go.mod +++ b/go.mod @@ -24,32 +24,29 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.1 golang.org/x/mod v0.6.0 - gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/go-playground/validator.v9 v9.31.0 gopkg.in/h2non/filetype.v1 v1.0.5 ) require ( - github.com/gabriel-vasile/mimetype v1.4.0 + github.com/gabriel-vasile/mimetype v1.4.1 github.com/golang-jwt/jwt/v4 v4.4.1 github.com/lestrrat-go/jwx v1.2.25 github.com/nyaruka/librato v1.0.0 - github.com/nyaruka/redisx v0.2.2 - github.com/patrickmn/go-cache v2.1.0+incompatible gopkg.in/go-playground/assert.v1 v1.2.1 ) require ( - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d // indirect - github.com/goccy/go-json v0.9.7 // indirect github.com/antchfx/xpath v1.2.1 // indirect github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d // indirect github.com/fatih/structs v1.1.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.1 // indirect github.com/getsentry/raven-go v0.2.0 // indirect github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/goccy/go-json v0.9.7 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -63,17 +60,15 @@ require ( github.com/lestrrat-go/option v1.0.0 // indirect github.com/naoina/go-stringutil v0.1.0 // indirect github.com/naoina/toml v0.1.1 // indirect - golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f // indirect - github.com/nyaruka/librato v1.0.0 // indirect github.com/nyaruka/phonenumbers v1.1.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect + golang.org/x/crypto v0.1.0 // indirect golang.org/x/net v0.2.0 // indirect golang.org/x/sys v0.2.0 // indirect golang.org/x/text v0.4.0 // indirect google.golang.org/protobuf v1.28.1 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/nyaruka/gocommon => github.com/Ilhasoft/gocommon v1.22.2-weni +//replace github.com/nyaruka/gocommon => github.com/Ilhasoft/gocommon v1.22.2-weni diff --git a/go.sum b/go.sum index f378a55ba..219d6f77b 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,9 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d h1:1iy2qD6JEhHKKhUOA9IWs7mjco7lnw2qx8FsRI2wirE= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/dghubble/oauth1 v0.7.1 h1:JjbOVSVVkms9A4h/sTQy5Jb2nFuAAVb2qVYgenJPyrE= github.com/dghubble/oauth1 v0.7.1/go.mod h1:0eEzON0UY/OLACQrmnjgJjmvCGXzjBCsZqL1kWDXtF0= github.com/evalphobia/logrus_sentry v0.8.2 h1:dotxHq+YLZsT1Bb45bB5UQbfCh3gM/nFFetyN46VoDQ= @@ -31,8 +34,12 @@ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/j github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ= +github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -79,7 +86,6 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.10 h1:MLn+5bFRlWMGoSRmJour3CL1w/qL96mvipqpwQW/Sfk= github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= @@ -130,11 +136,15 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -146,6 +156,7 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 251748267..eb35a1253 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -464,8 +464,6 @@ func (h *handler) processCloudWhatsAppPayload(ctx context.Context, channel couri // the list of data we will return in our response data := make([]interface{}, 0, 2) - token := h.Server().Config().WhatsappAdminSystemUserToken - var contactNames = make(map[string]string) // for each entry @@ -852,10 +850,10 @@ func (h *handler) processFacebookInstagramPayload(ctx context.Context, channel c text := strings.Join(payloads[:], "|") - ev := h.Backend().NewIncomingMsg(channel, urn, text).WithReceivedOn(date) + ev := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithReceivedOn(date) event := h.Backend().CheckExternalIDSeen(ev) - err := h.Backend().WriteMsg(ctx, event) + err := h.Backend().WriteMsg(ctx, event, clog) if err != nil { return nil, nil, err } @@ -1072,10 +1070,7 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.Msg, } req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - rr, err := utils.MakeHTTPRequest(req) - - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) - status.AddLog(log) + _, _, err = handlers.RequestHTTP(req, clog) if err != nil { return status, nil } @@ -1319,7 +1314,6 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, // can't do anything without an access token accessToken := h.Server().Config().WhatsappAdminSystemUserToken - start := time.Now() hasNewURN := false hasCaption := false @@ -1329,8 +1323,6 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) - hasCaption := false - msgParts := make([]string, 0) if msg.Text() != "" { msgParts = handlers.SplitMsgByChannel(msg.Channel(), msg.Text(), maxMsgLengthWAC) @@ -1583,7 +1575,7 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, zeroIndex = true } payloadAudio = wacMTPayload{MessagingProduct: "whatsapp", RecipientType: "individual", To: msg.URN().Path(), Type: "audio", Audio: &wacMTMedia{Link: attURL}} - status, err := requestWAC(payloadAudio, accessToken, status, wacPhoneURL, zeroIndex, clog) + status, _, err := requestWAC(payloadAudio, accessToken, status, wacPhoneURL, zeroIndex, clog) if err != nil { return status, nil } @@ -1668,7 +1660,7 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, zeroIndex = true } - status, err := requestWAC(payload, accessToken, status, wacPhoneURL, zeroIndex, clog) + status, respPayload, err := requestWAC(payload, accessToken, status, wacPhoneURL, zeroIndex, clog) if err != nil { return status, err } @@ -1682,8 +1674,7 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, } err = status.SetUpdatedURN(msg.URN(), toUpdateURN) if err != nil { - log := courier.NewChannelLogFromError("unable to update contact URN for a new based on wa_id", msg.Channel(), msg.ID(), time.Since(start), err) - status.AddLog(log) + clog.Error(courier.ErrorResponseUnexpected("unable to update contact URN for a new based on wa_id")) } hasNewURN = true } @@ -1695,15 +1686,15 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, return status, nil } -func requestWAC(payload wacMTPayload, accessToken string, status courier.MsgStatus, wacPhoneURL *url.URL, zeroIndex bool, clog *courier.ChannelLog) (courier.MsgStatus, error) { +func requestWAC(payload wacMTPayload, accessToken string, status courier.MsgStatus, wacPhoneURL *url.URL, zeroIndex bool, clog *courier.ChannelLog) (courier.MsgStatus, *wacMTResponse, error) { jsonBody, err := json.Marshal(payload) if err != nil { - return status, err + return status, nil, err } req, err := http.NewRequest(http.MethodPost, wacPhoneURL.String(), bytes.NewReader(jsonBody)) if err != nil { - return nil, err + return nil, nil, err } req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken)) @@ -1715,12 +1706,12 @@ func requestWAC(payload wacMTPayload, accessToken string, status courier.MsgStat err = json.Unmarshal(respBody, respPayload) if err != nil { clog.Error(courier.ErrorResponseUnparseable("JSON")) - return status, nil + return status, nil, nil } if respPayload.Error.Code != 0 { clog.Error(courier.ErrorExternal(strconv.Itoa(respPayload.Error.Code), respPayload.Error.Message)) - return status, nil + return status, nil, nil } externalID := respPayload.Messages[0].ID @@ -1729,7 +1720,7 @@ func requestWAC(payload wacMTPayload, accessToken string, status courier.MsgStat } // this was wired successfully status.SetStatus(courier.MsgWired) - return status, nil + return status, respPayload, nil } // DescribeURN looks up URN metadata for new contacts diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index 4398dd538..d15e392f0 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -11,6 +11,7 @@ import ( "time" "github.com/nyaruka/courier" + "github.com/nyaruka/courier/handlers" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/httpx" @@ -1470,7 +1471,9 @@ var SendTestCasesWAC = []ChannelSendTestCase{ func TestSending(t *testing.T) { // shorter max msg length for testing - maxMsgLength = 100 + maxMsgLengthFBA = 100 + maxMsgLengthIG = 100 + maxMsgLengthWAC = 100 var ChannelFBA = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "FBA", "12345", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}) var ChannelIG = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "IG", "12345", "", map[string]interface{}{courier.ConfigAuthToken: "a123"}) diff --git a/handlers/slack/slack.go b/handlers/slack/slack.go index 39c9042c9..432e3036b 100644 --- a/handlers/slack/slack.go +++ b/handlers/slack/slack.go @@ -6,11 +6,8 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "mime/multipart" "net/http" - "net/url" - "strconv" "strings" "time" @@ -72,77 +69,16 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } - if strings.HasPrefix(string(body), "payload") { - jsonStr, err = url.QueryUnescape(string(body)[8:]) - if err != nil { - return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) - } - - if err := json.Unmarshal([]byte(jsonStr), &payloadI); err != nil { - return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) - } - } else { - if err := json.Unmarshal(body, &payload); err != nil { - return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) - } - } - - if payloadI.Actions != nil && payload.Event.BotID == "" { - ts := strings.Split(payloadI.Actions[0].ActionTs, ".") - i, err := strconv.ParseInt(ts[0], 10, 64) - if err != nil { - return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) - } - date := time.Unix(int64(i), 0) - - var userName string - var path string - - if payloadI.Channel.Name != "directmessage" { //if is a message from a slack channel that bot is in - path = payloadI.Channel.ID - } else { // if is a direct message from a user - path = payloadI.User.ID - userInfo, log, err := getUserInfo(path, channel) - if err != nil { - h.Backend().WriteChannelLogs(ctx, []*courier.ChannelLog{log}) - return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) - } - userName = userInfo.User.RealName - } - - urn, err := urns.NewURNFromParts(urns.SlackScheme, path, "", "") - if err != nil { - return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) - } - text := payloadI.Actions[0].Text.Text - msg := h.Backend().NewIncomingMsg(channel, urn, text).WithContactName(userName).WithReceivedOn(date) - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) - } - if payload.Type == "url_verification" { return handleURLVerification(ctx, channel, w, r, payload) } // if event is not a message or is from the bot ignore it - if strings.Contains(payload.Event.Type, "message") && payload.Event.BotID == "" { + if payload.Event.Type == "message" && payload.Event.BotID == "" && payload.Event.ChannelType == "im" { date := time.Unix(int64(payload.EventTime), 0) - var userName string - var path string - if payload.Event.ChannelType == "channel" { //if is a message from a slack channel that bot is in - path = payload.Event.Channel - } else if payload.Event.ChannelType == "im" { // if is a direct message from a user - path = payload.Event.User - userInfo, log, err := getUserInfo(payload.Event.User, channel) - if err != nil { - h.Backend().WriteChannelLogs(ctx, []*courier.ChannelLog{log}) - return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) - } - userName = userInfo.User.RealName - } - - urn, err := urns.NewURNFromParts(urns.SlackScheme, path, "", userName) + urn, err := urns.NewURNFromParts(urns.SlackScheme, payload.Event.User, "", "") if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } @@ -158,7 +94,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } text := payload.Event.Text - msg := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithReceivedOn(date).WithExternalID(payload.EventID).WithContactName(userName) + msg := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithReceivedOn(date).WithExternalID(payload.EventID) for _, attURL := range attachmentURLs { msg.WithAttachment(attURL) @@ -218,32 +154,28 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann return nil, fmt.Errorf("missing bot token for SL/slack channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) hasError := true for _, attachment := range msg.Attachments() { - fileAttachment, log, err := parseAttachmentToFileParams(msg, attachment) + fileAttachment, err := parseAttachmentToFileParams(msg, attachment, clog) hasError = err != nil - status.AddLog(log) if fileAttachment != nil { - log, err = sendFilePart(msg, botToken, fileAttachment) + err = sendFilePart(msg, botToken, fileAttachment, clog) hasError = err != nil - status.AddLog(log) } } if len(msg.QuickReplies()) != 0 { - log, err := sendQuickReplies(msg, botToken) + _, err := sendQuickReplies(msg, botToken, clog) hasError = err != nil - status.AddLog(log) } if msg.Text() != "" && len(msg.QuickReplies()) == 0 { - log, err := sendTextMsgPart(msg, botToken) + err := sendTextMsgPart(msg, botToken, clog) hasError = err != nil - status.AddLog(log) } if !hasError { @@ -273,17 +205,18 @@ func sendTextMsgPart(msg courier.Msg, token string, clog *courier.ChannelLog) er req.Header.Set("Content-Type", "application/json; charset=utf-8") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) - rr, err := utils.MakeHTTPRequest(req) - - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) + resp, respBody, err := handlers.RequestHTTP(req, clog) + if err != nil || resp.StatusCode/100 != 2 { + return errors.New("error sending message") + } - ok, err := jsonparser.GetBoolean([]byte(rr.Body), "ok") + ok, err := jsonparser.GetBoolean(respBody, "ok") if err != nil { return err } if !ok { - errDescription, err := jsonparser.GetString([]byte(rr.Body), "error") + errDescription, err := jsonparser.GetString(respBody, "error") if err != nil { return err } @@ -360,7 +293,7 @@ func sendFilePart(msg courier.Msg, token string, fileParams *FileParams, clog *c return nil } -func sendQuickReplies(msg courier.Msg, botToken string) (*courier.ChannelLog, error) { +func sendQuickReplies(msg courier.Msg, botToken string, clog *courier.ChannelLog) (*courier.ChannelLog, error) { sendURL := apiURL + "/chat.postMessage" payload := &mtPayload{ @@ -408,55 +341,23 @@ func sendQuickReplies(msg courier.Msg, botToken string) (*courier.ChannelLog, er req.Header.Set("Content-Type", "application/json; charset=utf-8") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", botToken)) - rr, err := utils.MakeHTTPRequest(req) - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) - if err != nil { - return log, err + resp, respBody, err := handlers.RequestHTTP(req, clog) + if err != nil || resp.StatusCode/100 != 2 { + return clog, errors.New("error uploading file to slack") } - ok, err := jsonparser.GetBoolean([]byte(rr.Body), "ok") + ok, err := jsonparser.GetBoolean(respBody, "ok") if err != nil { - return log, err + return clog, err } if !ok { - _, err := jsonparser.GetString([]byte(rr.Body), "error") + _, err := jsonparser.GetString(respBody, "error") if err != nil { - return log, err + return clog, err } } - return log, nil -} - -func getUserInfo(userSlackID string, channel courier.Channel) (*UserInfo, *courier.ChannelLog, error) { - resource := "/users.info" - urlStr := apiURL + resource - - req, err := http.NewRequest(http.MethodGet, urlStr, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - req.Header.Add("Authorization", "Bearer "+channel.StringConfigForKey(configBotToken, "")) - - q := req.URL.Query() - q.Add("user", userSlackID) - req.URL.RawQuery = q.Encode() - - rr, err := utils.MakeHTTPRequest(req) - if err != nil { - log := courier.NewChannelLogFromRR("Get User info", channel, courier.NilMsgID, rr).WithError("Request User Info Error", err) - return nil, log, err - } - - var uInfo *UserInfo - if err := json.Unmarshal(rr.Body, &uInfo); err != nil { - log := courier.NewChannelLogFromRR("Get User info", channel, courier.NilMsgID, rr).WithError("Unmarshal User Info Error", err) - return nil, log, err - } - - return uInfo, nil, nil + return clog, nil } // DescribeURN handles Slack user details @@ -591,40 +492,6 @@ type FileParams struct { Channels string `json:"channels,omitempty"` } -// UserInfo is a struct that represents the response from request in users.info slack api method, more information see https://api.slack.com/methods/users.info. -type UserInfo struct { - Ok bool `json:"ok"` - User struct { - ID string `json:"id"` - TeamID string `json:"team_id"` - Name string `json:"name"` - Deleted bool `json:"deleted"` - Color string `json:"color"` - RealName string `json:"real_name"` - Tz string `json:"tz"` - TzLabel string `json:"tz_label"` - TzOffset int `json:"tz_offset"` - Profile struct { - AvatarHash string `json:"avatar_hash"` - StatusText string `json:"status_text"` - StatusEmoji string `json:"status_emoji"` - RealName string `json:"real_name"` - DisplayName string `json:"display_name"` - RealNameNormalized string `json:"real_name_normalized"` - DisplayNameNormalized string `json:"display_name_normalized"` - Email string `json:"email"` - ImageOriginal string `json:"image_original"` - Image24 string `json:"image_24"` - Image32 string `json:"image_32"` - Image48 string `json:"image_48"` - Image72 string `json:"image_72"` - Image192 string `json:"image_192"` - Image512 string `json:"image_512"` - Team string `json:"team"` - } `json:"profile"` - } `json:"user"` -} - // UserInfo is a struct that represents the response from request in users.info slack api method. // https://api.slack.com/methods/users.info. type UserInfo struct { diff --git a/handlers/teams/teams.go b/handlers/teams/teams.go index d74782949..a10073396 100644 --- a/handlers/teams/teams.go +++ b/handlers/teams/teams.go @@ -151,7 +151,7 @@ func validateToken(channel courier.Channel, w http.ResponseWriter, r *http.Reque return nil } -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &Activity{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -194,7 +194,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } } - ev := h.Backend().NewIncomingMsg(channel, urn, text).WithExternalID(payload.Id).WithReceivedOn(date) + ev := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithExternalID(payload.Id).WithReceivedOn(date) event := h.Backend().CheckExternalIDSeen(ev) // add any attachment URL found @@ -202,7 +202,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h event.WithAttachment(attURL) } - err := h.Backend().WriteMsg(ctx, event) + err := h.Backend().WriteMsg(ctx, event, clog) if err != nil { return nil, err } @@ -255,14 +255,14 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer "+token) - rr, err := utils.MakeHTTPRequest(req) + _, respBody, err := handlers.RequestHTTP(req, clog) if err != nil { return nil, err } var body ConversationAccount - err = json.Unmarshal(rr.Body, &body) + err = json.Unmarshal(respBody, &body) if err != nil { return nil, err } @@ -272,7 +272,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } - event := h.Backend().NewChannelEvent(channel, courier.NewConversation, urn).WithOccurredOn(date) + event := h.Backend().NewChannelEvent(channel, courier.NewConversation, urn, clog).WithOccurredOn(date) events = append(events, event) data = append(data, courier.NewEventReceiveData(event)) } @@ -281,7 +281,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h data = append(data, courier.NewInfoData("ignoring messageReaction")) } - return events, courier.WriteDataResponse(ctx, w, http.StatusOK, "Events Handled", data) + return events, courier.WriteDataResponse(w, http.StatusOK, "Events Handled", data) } type mtPayload struct { @@ -339,14 +339,14 @@ type Activity struct { Timestamp string `json:"timestamp,omitempty"` } -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { token := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if token == "" { return nil, fmt.Errorf("missing token for TM channel") } - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored) + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgErrored, clog) payload := Activity{} @@ -382,25 +382,21 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer "+token) - rr, err := utils.MakeHTTPRequest(req) - - // record our status and log - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), rr).WithError("Message Send Error", err) - status.AddLog(log) + _, respBody, err := handlers.RequestHTTP(req, clog) if err != nil { return status, err } status.SetStatus(courier.MsgWired) - externalID, err := jsonparser.GetString(rr.Body, "id") + externalID, err := jsonparser.GetString(respBody, "id") if err != nil { - log.WithError("Message Send Error", errors.Errorf("unable to get message_id from body")) + logrus.WithError(errors.Errorf("unable to get message_id from body")) return status, nil } status.SetExternalID(externalID) return status, nil } -func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN) (map[string]string, error) { +func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn urns.URN, clog *courier.ChannelLog) (map[string]string, error) { accessToken := channel.StringConfigForKey(courier.ConfigAuthToken, "") if accessToken == "" { @@ -414,14 +410,14 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn req, _ := http.NewRequest(http.MethodGet, url, nil) req.Header.Set("Authorization", "Bearer "+accessToken) - rr, err := utils.MakeHTTPRequest(req) + resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil { - return nil, fmt.Errorf("unable to look up contact data:%s\n%s", err, rr.Response) + return nil, fmt.Errorf("unable to look up contact data:%s\n%s", err, resp) } // read our first and last name - givenName, _ := jsonparser.GetString(rr.Body, "[0]", "givenName") - surname, _ := jsonparser.GetString(rr.Body, "[0]", "surname") + givenName, _ := jsonparser.GetString(respBody, "[0]", "givenName") + surname, _ := jsonparser.GetString(respBody, "[0]", "surname") return map[string]string{"name": utils.JoinNonEmpty(" ", givenName, surname)}, nil } diff --git a/handlers/teams/teams_test.go b/handlers/teams/teams_test.go index 444df1611..872661379 100644 --- a/handlers/teams/teams_test.go +++ b/handlers/teams/teams_test.go @@ -10,6 +10,7 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" "github.com/nyaruka/gocommon/urns" "gopkg.in/go-playground/assert.v1" ) @@ -17,7 +18,7 @@ import ( var access_token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImFiYzEyMyJ9.eyJpc3MiOiJodHRwczovL2FwaS5ib3RmcmFtZXdvcmsuY29tIiwic2VydmljZXVybCI6Imh0dHBzOi8vc21iYS50cmFmZmljbWFuYWdlci5uZXQvYnIvIiwiYXVkIjoiMTU5NiJ9.hqKdNdlB0NX6jtwkN96jI-kIiWTWPDIA1K7oo56tVsRBmMycyNNHrsGbKrEw7dccLjATmimpk4x0J_umaJZ5mcK5S5F7b4hkGHFIRWc4vaMjxCl6VSJ6E6DTRnQwfrfTF0AerHSO1iABI2YAlbdMV3ahxGzzNkaqnIX496G2IKwiYziOumo4M0gfOt-MqNkOJKvnSRfB7pikSATaSQiaFmrA5A8bH0AbaM9znPIRxHyrKqlFlrpWkPSiUPOS3aHQeD8kVGk7RNEWtOk26sXfUIjHp8ZYExIClBEmc6QPAf2-FAuwsw-S8YDLwsiycJ0gEO8MYPZWn8gXR_sVIwLMMg" var testChannels = []courier.Channel{ - courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "TM", "2022", "US", map[string]interface{}{"auth_token": access_token, "tenantID": "cba321", "botID": "0123", "appID": "1596"}), + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c568c", "TM", "2022", "US", map[string]interface{}{"auth_token": access_token, "tenantID": "cba321", "botID": "0123", "appID": "1596"}), } var helloMsg = `{ @@ -120,78 +121,78 @@ var messageReaction = `{ var testCases = []ChannelHandleTestCase{ { - Label: "Receive Message", - URL: "/c/tm/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", - Data: helloMsg, - Status: 200, - Response: "Handled", - Text: Sp("Hello World"), - URN: Sp("teams:a:2811:serviceURL:https://smba.trafficmanager.net/br/"), - ExternalID: Sp("56834"), - Date: Tp(time.Date(2022, 6, 6, 16, 51, 00, 0000000, time.UTC)), - Headers: map[string]string{"Authorization": "Bearer " + access_token}, - NoQueueErrorCheck: true, + Label: "Receive Message", + URL: "/c/tm/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", + Data: helloMsg, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgText: Sp("Hello World"), + ExpectedURN: "teams:a:2811:serviceURL:https://smba.trafficmanager.net/br/", + ExpectedExternalID: "56834", + ExpectedDate: time.Date(2022, 6, 6, 16, 51, 00, 0000000, time.UTC), + Headers: map[string]string{"Authorization": "Bearer " + access_token}, + NoQueueErrorCheck: true, }, { - Label: "Receive Attachment Image", - URL: "/c/tm/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", - Data: attachment, - Status: 200, - Response: "Handled", - Text: Sp("Hello World"), - Attachments: []string{"https://image-url/foo.png"}, - URN: Sp("teams:a:2811:serviceURL:https://smba.trafficmanager.net/br/"), - ExternalID: Sp("56834"), - Date: Tp(time.Date(2022, 6, 6, 16, 51, 00, 0000000, time.UTC)), - Headers: map[string]string{"Authorization": "Bearer " + access_token}, - NoQueueErrorCheck: true, + Label: "Receive Attachment Image", + URL: "/c/tm/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", + Data: attachment, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgText: Sp("Hello World"), + ExpectedAttachments: []string{"https://image-url/foo.png"}, + ExpectedURN: "teams:a:2811:serviceURL:https://smba.trafficmanager.net/br/", + ExpectedExternalID: "56834", + ExpectedDate: time.Date(2022, 6, 6, 16, 51, 00, 0000000, time.UTC), + Headers: map[string]string{"Authorization": "Bearer " + access_token}, + NoQueueErrorCheck: true, }, { - Label: "Receive Attachment Video", - URL: "/c/tm/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", - Data: attachmentVideo, - Status: 200, - Response: "Handled", - Text: Sp("Hello World"), - Attachments: []string{"https://video-url/foo.mp4"}, - URN: Sp("teams:a:2811:serviceURL:https://smba.trafficmanager.net/br/"), - ExternalID: Sp("56834"), - Date: Tp(time.Date(2022, 6, 6, 16, 51, 00, 0000000, time.UTC)), - Headers: map[string]string{"Authorization": "Bearer " + access_token}, - NoQueueErrorCheck: true, + Label: "Receive Attachment Video", + URL: "/c/tm/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", + Data: attachmentVideo, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgText: Sp("Hello World"), + ExpectedAttachments: []string{"https://video-url/foo.mp4"}, + ExpectedURN: "teams:a:2811:serviceURL:https://smba.trafficmanager.net/br/", + ExpectedExternalID: "56834", + ExpectedDate: time.Date(2022, 6, 6, 16, 51, 00, 0000000, time.UTC), + Headers: map[string]string{"Authorization": "Bearer " + access_token}, + NoQueueErrorCheck: true, }, { - Label: "Receive Attachment Document", - URL: "/c/tm/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", - Data: attachmentDocument, - Status: 200, - Response: "Handled", - Text: Sp("Hello World"), - Attachments: []string{"https://document-url/foo.pdf"}, - URN: Sp("teams:a:2811:serviceURL:https://smba.trafficmanager.net/br/"), - ExternalID: Sp("56834"), - Date: Tp(time.Date(2022, 6, 6, 16, 51, 00, 0000000, time.UTC)), - Headers: map[string]string{"Authorization": "Bearer " + access_token}, - NoQueueErrorCheck: true, + Label: "Receive Attachment Document", + URL: "/c/tm/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", + Data: attachmentDocument, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + ExpectedMsgText: Sp("Hello World"), + ExpectedAttachments: []string{"https://document-url/foo.pdf"}, + ExpectedURN: "teams:a:2811:serviceURL:https://smba.trafficmanager.net/br/", + ExpectedExternalID: "56834", + ExpectedDate: time.Date(2022, 6, 6, 16, 51, 00, 0000000, time.UTC), + Headers: map[string]string{"Authorization": "Bearer " + access_token}, + NoQueueErrorCheck: true, }, { - Label: "Receive Message Reaction", - URL: "/c/tm/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", - Data: messageReaction, - Status: 200, - URN: Sp(""), - Response: "ignoring messageReaction", - Headers: map[string]string{"Authorization": "Bearer " + access_token}, - NoQueueErrorCheck: true, + Label: "Receive Message Reaction", + URL: "/c/tm/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", + Data: messageReaction, + ExpectedRespStatus: 200, + ExpectedURN: "", + ExpectedBodyContains: "ignoring messageReaction", + Headers: map[string]string{"Authorization": "Bearer " + access_token}, + NoQueueErrorCheck: true, }, { - Label: "Receive Conversation Update", - URL: "/c/tm/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", - Data: "", - Status: 200, - Response: "Handled", - Headers: map[string]string{"Authorization": "Bearer " + access_token}, - NoQueueErrorCheck: true, + Label: "Receive Conversation Update", + URL: "/c/tm/8eb23e93-5ecb-45ba-b726-3b064e0c568c/receive", + Data: "", + ExpectedRespStatus: 200, + ExpectedBodyContains: "Handled", + Headers: map[string]string{"Authorization": "Bearer " + access_token}, + NoQueueErrorCheck: true, }, } @@ -259,53 +260,53 @@ func newConversationUpdateTC(newUrl string, testCase []ChannelHandleTestCase) [] var defaultSendTestCases = []ChannelSendTestCase{ { - Label: "Plain Send", - Text: "Simple Message", - URN: "teams:a:2022:serviceURL:https://smba.trafficmanager.net/br/", - Status: "W", ExternalID: "1234567890", - ResponseBody: `{id:"1234567890"}`, ResponseStatus: 200, + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "teams:a:2022:serviceURL:https://smba.trafficmanager.net/br/", + ExpectedMsgStatus: "W", ExpectedExternalID: "1234567890", + MockResponseBody: `{id:"1234567890"}`, MockResponseStatus: 200, }, {Label: "Send Photo", - URN: "teams:a:2022:serviceURL:https://smba.trafficmanager.net/br/", Attachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - Status: "W", ExternalID: "1234567890", - ResponseBody: `{"id": "1234567890"}`, ResponseStatus: 200, + MsgURN: "teams:a:2022:serviceURL:https://smba.trafficmanager.net/br/", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + ExpectedMsgStatus: "W", ExpectedExternalID: "1234567890", + MockResponseBody: `{"id": "1234567890"}`, MockResponseStatus: 200, }, {Label: "Send Video", - URN: "teams:a:2022:serviceURL:https://smba.trafficmanager.net/br/", Attachments: []string{"video/mp4:https://foo.bar/video.mp4"}, - Status: "W", ExternalID: "1234567890", - ResponseBody: `{"id": "1234567890"}`, ResponseStatus: 200, + MsgURN: "teams:a:2022:serviceURL:https://smba.trafficmanager.net/br/", MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, + ExpectedMsgStatus: "W", ExpectedExternalID: "1234567890", + MockResponseBody: `{"id": "1234567890"}`, MockResponseStatus: 200, }, {Label: "Send Document", - URN: "teams:a:2022:serviceURL:https://smba.trafficmanager.net/br/", Attachments: []string{"application/pdf:https://foo.bar/document.pdf"}, - Status: "W", ExternalID: "1234567890", - ResponseBody: `{"id": "1234567890"}`, ResponseStatus: 200, + MsgURN: "teams:a:2022:serviceURL:https://smba.trafficmanager.net/br/", MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, + ExpectedMsgStatus: "W", ExpectedExternalID: "1234567890", + MockResponseBody: `{"id": "1234567890"}`, MockResponseStatus: 200, }, } func newSendTestCases(testSendCases []ChannelSendTestCase, url string) []ChannelSendTestCase { var newtestSendCases []ChannelSendTestCase for _, tc := range testSendCases { - spTC := strings.Split(tc.URN, ":serviceURL:") + spTC := strings.Split(tc.MsgURN, ":serviceURL:") newURN := spTC[0] + ":serviceURL:" + url + "/" - tc.URN = newURN + tc.MsgURN = newURN newtestSendCases = append(newtestSendCases, tc) } return newtestSendCases } func TestSending(t *testing.T) { - var defaultChannel = courier.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TM", "2022", "US", + var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "TM", "2022", "US", map[string]interface{}{courier.ConfigAuthToken: access_token, "tenantID": "cba321", "botID": "0123", "appID": "1596"}) serviceTM := buildMockTeams() newSendTestCases := newSendTestCases(defaultSendTestCases, serviceTM.URL) - RunChannelSendTestCases(t, defaultChannel, newHandler(), newSendTestCases, nil) + RunChannelSendTestCases(t, defaultChannel, newHandler(), newSendTestCases, nil, nil) serviceTM.Close() } func TestDescribe(t *testing.T) { server := buildMockTeams() - + clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], nil) handler := newHandler().(courier.URNDescriber) tcs := []struct { urn urns.URN @@ -313,7 +314,7 @@ func TestDescribe(t *testing.T) { }{{urns.URN("teams:a:2022:serviceURL:" + string(server.URL) + "/"), map[string]string{"name": "John Doe"}}} for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), testChannels[0], tc.urn) + metadata, _ := handler.DescribeURN(context.Background(), testChannels[0], tc.urn, clog) assert.Equal(t, metadata, tc.metadata) } server.Close() diff --git a/handlers/test.go b/handlers/test.go index 8075583fc..d476f61a7 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -70,47 +70,6 @@ type MockedResponse struct { Body string } -// ChannelSendTestCase defines the test values for a particular test case -type ChannelSendTestCase struct { - Label string - - Text string - URN string - URNAuth string - Attachments []string - QuickReplies []string - Topic string - HighPriority bool - ResponseToExternalID string - Metadata json.RawMessage - Flow *courier.FlowReference - - ResponseStatus int - ResponseBody string - Responses map[MockedRequest]MockedResponse - - Path string - URLParams map[string]string - PostParams map[string]string - RequestBody string - Headers map[string]string - - Error string - Status string - ExternalID string - - Stopped bool - - ContactURNs map[string]bool - - SendPrep SendPrepFunc - NewURN string - TextLanguage string -} - -// Sp is a utility method to get the pointer to the passed in string -func Sp(str interface{}) *string { asStr := fmt.Sprintf("%s", str); return &asStr } - // Tp is utility method to get the pointer to the passed in time func Tp(tm time.Time) *time.Time { return &tm } @@ -123,6 +82,8 @@ func ensureTestServerUp(host string) { } time.Sleep(time.Microsecond * 100) } +} + func (m MockedRequest) Matches(r *http.Request, body []byte) bool { return m.Method == r.Method && m.Path == r.URL.Path && m.RawQuery == r.URL.RawQuery && (m.Body == string(body) || (m.BodyContains != "" && strings.Contains(string(body), m.BodyContains))) } diff --git a/handlers/webhook.go b/handlers/webhook.go index c21a22a29..4188db79c 100644 --- a/handlers/webhook.go +++ b/handlers/webhook.go @@ -7,9 +7,11 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/utils" + "github.com/nyaruka/gocommon/httpx" + "github.com/pkg/errors" ) -func SendWebhooks(channel courier.Channel, r *http.Request, configWebhook interface{}) error { +func SendWebhooks(channel courier.Channel, r *http.Request, configWebhook interface{}, clog *courier.ChannelLog) error { webhook, ok := configWebhook.(map[string]interface{}) if !ok { return fmt.Errorf("conversion error") @@ -37,10 +39,12 @@ func SendWebhooks(channel courier.Channel, r *http.Request, configWebhook interf req.Header.Set(name, value.(string)) } - resp, err := utils.MakeHTTPRequest(req) - - if resp.StatusCode/100 != 2 { - return err + trace, err := httpx.DoTrace(utils.GetHTTPClient(), req, nil, nil, 1024) + if trace != nil { + clog.HTTP(trace) + } + if err != nil || trace.Response.StatusCode/100 != 2 { + return errors.Wrap(err, "status other than 200") } return nil diff --git a/handlers/weniwebchat/weniwebchat.go b/handlers/weniwebchat/weniwebchat.go index 7cbe36c48..92c9d38fb 100644 --- a/handlers/weniwebchat/weniwebchat.go +++ b/handlers/weniwebchat/weniwebchat.go @@ -13,8 +13,8 @@ import ( "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/urns" + "github.com/sirupsen/logrus" ) func init() { @@ -32,7 +32,7 @@ func newHandler() courier.ChannelHandler { // Initialize is called by the engine once everything is loaded func (h *handler) Initialize(s courier.Server) error { h.SetServer(s) - s.AddHandlerRoute(h, http.MethodPost, "receive", h.receiveMsg) + s.AddHandlerRoute(h, http.MethodPost, "receive", h.receiveEvent) return nil } @@ -52,7 +52,7 @@ type miMessage struct { Longitude string `json:"longitude,omitempty"` } -func (h *handler) receiveMsg(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) { payload := &miPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -92,13 +92,13 @@ func (h *handler) receiveMsg(ctx context.Context, channel courier.Channel, w htt // build message date := time.Unix(ts, 0).UTC() - msg := h.Backend().NewIncomingMsg(channel, urn, payload.Message.Text).WithReceivedOn(date).WithContactName(payload.From) + msg := h.Backend().NewIncomingMsg(channel, urn, payload.Message.Text, clog).WithReceivedOn(date).WithContactName(payload.From) if mediaURL != "" { msg.WithAttachment(mediaURL) } - return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r) + return handlers.WriteMsgsAndResponse(ctx, h, []courier.Msg{msg}, w, r, clog) } var timestamp = "" @@ -121,9 +121,8 @@ type moMessage struct { QuickReplies []string `json:"quick_replies,omitempty"` } -func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStatus, error) { - start := time.Now() - status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgSent) +func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.ChannelLog) (courier.MsgStatus, error) { + status := h.Backend().NewMsgStatusForID(msg.Channel(), msg.ID(), courier.MsgSent, clog) baseURL := msg.Channel().StringConfigForKey(courier.ConfigBaseURL, "") if baseURL == "" { @@ -132,8 +131,6 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat sendURL := fmt.Sprintf("%s/send", baseURL) - var logs []*courier.ChannelLog - payload := newOutgoingMessage("message", msg.URN().Path(), msg.Channel().Address(), msg.QuickReplies()) lenAttachments := len(msg.Attachments()) if lenAttachments > 0 { @@ -164,9 +161,7 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat MediaURL: attachmentURL, } } else { - elapsed := time.Since(start) - log := courier.NewChannelLogFromError("Error sending message", msg.Channel(), msg.ID(), elapsed, fmt.Errorf("unknown attachment mime type: %s", mimeType)) - logs = append(logs, log) + logrus.WithField("channel_uuid", msg.Channel().UUID().String()).Error("unknown attachment mime type: %s", mimeType) status.SetStatus(courier.MsgFailed) break attachmentsLoop } @@ -185,18 +180,16 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat var body []byte body, err := json.Marshal(&payload) if err != nil { - elapsed := time.Since(start) - log := courier.NewChannelLogFromError("Error sending message", msg.Channel(), msg.ID(), elapsed, err) - logs = append(logs, log) + logrus.WithField("channel_uuid", msg.Channel().UUID().String()).WithError(err).Error("Error sending message") status.SetStatus(courier.MsgFailed) break attachmentsLoop } req, _ := http.NewRequest(http.MethodPost, sendURL, bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") - res, err := utils.MakeHTTPRequest(req) - if res != nil { - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), res).WithError("Message Send Error", err) - logs = append(logs, log) + _, _, err = handlers.RequestHTTP(req, clog) + if err != nil { + logrus.WithField("channel_uuid", msg.Channel().UUID().String()).WithError(err).Error("Message Send Error") + status.SetStatus(courier.MsgFailed) } if err != nil { status.SetStatus(courier.MsgFailed) @@ -213,18 +206,13 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat // build request body, err := json.Marshal(&payload) if err != nil { - elapsed := time.Since(start) - log := courier.NewChannelLogFromError("Error sending message", msg.Channel(), msg.ID(), elapsed, err) - logs = append(logs, log) + logrus.WithField("channel_uuid", msg.Channel().UUID().String()).WithError(err).Error("Message Send Error") + status.SetStatus(courier.MsgFailed) status.SetStatus(courier.MsgFailed) } else { req, _ := http.NewRequest(http.MethodPost, sendURL, bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") - res, err := utils.MakeHTTPRequest(req) - if res != nil { - log := courier.NewChannelLogFromRR("Message Sent", msg.Channel(), msg.ID(), res).WithError("Message Send Error", err) - logs = append(logs, log) - } + _, _, err := handlers.RequestHTTP(req, clog) if err != nil { status.SetStatus(courier.MsgFailed) } @@ -232,10 +220,6 @@ func (h *handler) SendMsg(ctx context.Context, msg courier.Msg) (courier.MsgStat } - for _, log := range logs { - status.AddLog(log) - } - return status, nil } diff --git a/handlers/weniwebchat/weniwebchat_test.go b/handlers/weniwebchat/weniwebchat_test.go index f566671a0..037a23c8a 100644 --- a/handlers/weniwebchat/weniwebchat_test.go +++ b/handlers/weniwebchat/weniwebchat_test.go @@ -9,12 +9,13 @@ import ( "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" + "github.com/nyaruka/courier/test" ) const channelUUID = "8eb23e93-5ecb-45ba-b726-3b064e0c568c" var testChannels = []courier.Channel{ - courier.NewMockChannel(channelUUID, "WWC", "250788383383", "", map[string]interface{}{}), + test.NewMockChannel(channelUUID, "WWC", "250788383383", "", map[string]interface{}{}), } // ReceiveMsg test @@ -75,62 +76,62 @@ const ( var testCases = []ChannelHandleTestCase{ { - Label: "Receive Valid Text Msg", - URL: receiveURL, - Data: fmt.Sprintf(textMsgTemplate, "2345678", "1616586927", "Hello Test!"), - Name: Sp("2345678"), - URN: Sp("ext:2345678"), - Text: Sp("Hello Test!"), - Status: 200, - Response: "Accepted", + Label: "Receive Valid Text Msg", + URL: receiveURL, + Data: fmt.Sprintf(textMsgTemplate, "2345678", "1616586927", "Hello Test!"), + ExpectedContactName: Sp("2345678"), + ExpectedURN: "ext:2345678", + ExpectedMsgText: Sp("Hello Test!"), + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", }, { - Label: "Receive Valid Media", - URL: receiveURL, - Data: fmt.Sprintf(imgMsgTemplate, "2345678", "1616586927", "https://link.to/image.png", "My Caption"), - Name: Sp("2345678"), - URN: Sp("ext:2345678"), - Text: Sp("My Caption"), - Attachment: Sp("https://link.to/image.png"), - Status: 200, - Response: "Accepted", + Label: "Receive Valid Media", + URL: receiveURL, + Data: fmt.Sprintf(imgMsgTemplate, "2345678", "1616586927", "https://link.to/image.png", "My Caption"), + ExpectedContactName: Sp("2345678"), + ExpectedURN: "ext:2345678", + ExpectedMsgText: Sp("My Caption"), + ExpectedAttachments: []string{"https://link.to/image.png"}, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", }, { - Label: "Receive Valid Location", - URL: receiveURL, - Data: fmt.Sprintf(locationMsgTemplate, "2345678", "1616586927", "-9.6996104", "-35.7794614"), - Name: Sp("2345678"), - URN: Sp("ext:2345678"), - Attachment: Sp("geo:-9.6996104,-35.7794614"), - Status: 200, - Response: "Accepted", + Label: "Receive Valid Location", + URL: receiveURL, + Data: fmt.Sprintf(locationMsgTemplate, "2345678", "1616586927", "-9.6996104", "-35.7794614"), + ExpectedContactName: Sp("2345678"), + ExpectedURN: "ext:2345678", + ExpectedAttachments: []string{"geo:-9.6996104,-35.7794614"}, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", }, { - Label: "Receive Invalid JSON", - URL: receiveURL, - Data: "{}", - Status: 400, + Label: "Receive Invalid JSON", + URL: receiveURL, + Data: "{}", + ExpectedRespStatus: 400, }, { - Label: "Receive Text Msg With Blank Message Text", - URL: receiveURL, - Data: fmt.Sprintf(textMsgTemplate, "2345678", "1616586927", ""), - Status: 400, - Response: "blank message, media or location", + Label: "Receive Text Msg With Blank Message Text", + URL: receiveURL, + Data: fmt.Sprintf(textMsgTemplate, "2345678", "1616586927", ""), + ExpectedRespStatus: 400, + ExpectedBodyContains: "blank message, media or location", }, { - Label: "Receive Invalid Timestamp", - URL: receiveURL, - Data: fmt.Sprintf(textMsgTemplate, "2345678", "foo", "Hello Test!"), - Status: 400, - Response: "invalid timestamp: foo", + Label: "Receive Invalid Timestamp", + URL: receiveURL, + Data: fmt.Sprintf(textMsgTemplate, "2345678", "foo", "Hello Test!"), + ExpectedRespStatus: 400, + ExpectedBodyContains: "invalid timestamp: foo", }, { - Label: "Receive Invalid Message", - URL: receiveURL, - Data: invalidMsgTemplate, - Status: 200, - Response: "ignoring request, unknown message type", + Label: "Receive Invalid Message", + URL: receiveURL, + Data: invalidMsgTemplate, + ExpectedRespStatus: 200, + ExpectedBodyContains: "ignoring request, unknown message type", }, } @@ -145,7 +146,7 @@ func BenchmarkHandler(b *testing.B) { // SendMsg test func prepareSendMsg(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { - c.(*courier.MockChannel).SetConfig(courier.ConfigBaseURL, s.URL) + c.(*test.MockChannel).SetConfig(courier.ConfigBaseURL, s.URL) timestamp = "1616700878" } @@ -155,8 +156,8 @@ func mockAttachmentURLs(mediaServer *httptest.Server, testCases []ChannelSendTes for i, testCase := range testCases { mockedCase := testCase - for j, attachment := range testCase.Attachments { - mockedCase.Attachments[j] = strings.Replace(attachment, "https://foo.bar", mediaServer.URL, 1) + for j, attachment := range testCase.MsgAttachments { + mockedCase.MsgAttachments[j] = strings.Replace(attachment, "https://foo.bar", mediaServer.URL, 1) } casesWithMockedUrls[i] = mockedCase } @@ -165,76 +166,76 @@ func mockAttachmentURLs(mediaServer *httptest.Server, testCases []ChannelSendTes var sendTestCases = []ChannelSendTestCase{ { - Label: "Plain Send", - Text: "Simple Message", - URN: "ext:371298371241", - Status: string(courier.MsgSent), - Path: "/send", - Headers: map[string]string{"Content-type": "application/json"}, - RequestBody: `{"type":"message","to":"371298371241","from":"250788383383","message":{"type":"text","timestamp":"1616700878","text":"Simple Message"}}`, - ResponseStatus: 200, - SendPrep: prepareSendMsg, + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "ext:371298371241", + ExpectedMsgStatus: courier.MsgSent, + ExpectedRequestPath: "/send", + ExpectedHeaders: map[string]string{"Content-type": "application/json"}, + ExpectedRequestBody: `{"type":"message","to":"371298371241","from":"250788383383","message":{"type":"text","timestamp":"1616700878","text":"Simple Message"}}`, + MockResponseStatus: 200, + SendPrep: prepareSendMsg, }, { - Label: "Unicode Send", - Text: "☺", - URN: "ext:371298371241", - Status: string(courier.MsgSent), - Path: "/send", - Headers: map[string]string{"Content-type": "application/json"}, - RequestBody: `{"type":"message","to":"371298371241","from":"250788383383","message":{"type":"text","timestamp":"1616700878","text":"☺"}}`, - ResponseStatus: 200, - SendPrep: prepareSendMsg, + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "ext:371298371241", + ExpectedMsgStatus: courier.MsgSent, + ExpectedRequestPath: "/send", + ExpectedHeaders: map[string]string{"Content-type": "application/json"}, + ExpectedRequestBody: `{"type":"message","to":"371298371241","from":"250788383383","message":{"type":"text","timestamp":"1616700878","text":"☺"}}`, + MockResponseStatus: 200, + SendPrep: prepareSendMsg, }, { - Label: "invalid Text Send", - Text: "Error", - URN: "ext:371298371241", - Status: string(courier.MsgFailed), - Path: "/send", - Headers: map[string]string{"Content-type": "application/json"}, - RequestBody: `{"type":"message","to":"371298371241","from":"250788383383","message":{"type":"text","timestamp":"1616700878","text":"Error"}}`, - SendPrep: prepareSendMsg, + Label: "invalid Text Send", + MsgText: "Error", + MsgURN: "ext:371298371241", + ExpectedMsgStatus: courier.MsgFailed, + ExpectedRequestPath: "/send", + ExpectedHeaders: map[string]string{"Content-type": "application/json"}, + ExpectedRequestBody: `{"type":"message","to":"371298371241","from":"250788383383","message":{"type":"text","timestamp":"1616700878","text":"Error"}}`, + SendPrep: prepareSendMsg, }, { - Label: "Medias Send", - Text: "Medias", - Attachments: []string{ + Label: "Medias Send", + MsgText: "Medias", + MsgAttachments: []string{ "audio/mp3:https://foo.bar/audio.mp3", "application/pdf:https://foo.bar/file.pdf", "image/jpg:https://foo.bar/image.jpg", "video/mp4:https://foo.bar/video.mp4", }, - URN: "ext:371298371241", - Status: string(courier.MsgSent), - ResponseStatus: 200, - SendPrep: prepareSendMsg, + MsgURN: "ext:371298371241", + ExpectedMsgStatus: courier.MsgSent, + MockResponseStatus: 200, + SendPrep: prepareSendMsg, }, { - Label: "Invalid Media Type Send", - Text: "Medias", - Attachments: []string{"foo/bar:https://foo.bar/foo.bar"}, - URN: "ext:371298371241", - Status: string(courier.MsgFailed), - ResponseStatus: 400, - SendPrep: prepareSendMsg, + Label: "Invalid Media Type Send", + MsgText: "Medias", + MsgAttachments: []string{"foo/bar:https://foo.bar/foo.bar"}, + MsgURN: "ext:371298371241", + ExpectedMsgStatus: courier.MsgFailed, + MockResponseStatus: 400, + SendPrep: prepareSendMsg, }, { - Label: "Invalid Media Send", - Text: "Medias", - Attachments: []string{"image/png:https://foo.bar/image.png"}, - URN: "ext:371298371241", - Status: string(courier.MsgFailed), - SendPrep: prepareSendMsg, + Label: "Invalid Media Send", + MsgText: "Medias", + MsgAttachments: []string{"image/png:https://foo.bar/image.png"}, + MsgURN: "ext:371298371241", + ExpectedMsgStatus: courier.MsgFailed, + SendPrep: prepareSendMsg, }, { - Label: "No Timestamp Prepare", - Text: "No prepare", - URN: "ext:371298371241", - Status: string(courier.MsgSent), - ResponseStatus: 200, + Label: "No Timestamp Prepare", + MsgText: "No prepare", + MsgURN: "ext:371298371241", + ExpectedMsgStatus: courier.MsgSent, + MockResponseStatus: 200, SendPrep: func(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.Msg) { - c.(*courier.MockChannel).SetConfig(courier.ConfigBaseURL, s.URL) + c.(*test.MockChannel).SetConfig(courier.ConfigBaseURL, s.URL) timestamp = "" }, }, @@ -250,5 +251,5 @@ func TestSending(t *testing.T) { mockedSendTestCases := mockAttachmentURLs(mediaServer, sendTestCases) mediaServer.Close() - RunChannelSendTestCases(t, testChannels[0], newHandler(), mockedSendTestCases, nil) + RunChannelSendTestCases(t, testChannels[0], newHandler(), mockedSendTestCases, nil, nil) } diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index 2ef6ffff8..b48133d3b 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -178,10 +178,10 @@ type eventPayload struct { } // checkBlockedContact is a function to verify if the contact from msg has status blocked to return an error or not if it is active -func checkBlockedContact(payload *eventPayload, ctx context.Context, channel courier.Channel, h *handler) error { +func checkBlockedContact(payload *eventPayload, ctx context.Context, channel courier.Channel, h *handler, clog *courier.ChannelLog) error { if len(payload.Contacts) > 0 { if contactURN, err := urns.NewWhatsAppURN(payload.Contacts[0].WaID); err == nil { - if contact, err := h.Backend().GetContact(ctx, channel, contactURN, channel.StringConfigForKey(courier.ConfigAuthToken, ""), payload.Contacts[0].Profile.Name); err == nil { + if contact, err := h.Backend().GetContact(ctx, channel, contactURN, channel.StringConfigForKey(courier.ConfigAuthToken, ""), payload.Contacts[0].Profile.Name, clog); err == nil { c, err := json.Marshal(contact) if err != nil { return err @@ -211,7 +211,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } - err = checkBlockedContact(payload, ctx, channel, h) + err = checkBlockedContact(payload, ctx, channel, h, clog) if err != nil { return nil, err } @@ -339,7 +339,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h webhook := channel.ConfigForKey("webhook", nil) if webhook != nil { - er := handlers.SendWebhooks(channel, r, webhook) + er := handlers.SendWebhooks(channel, r, webhook, clog) if er != nil { courier.LogRequestError(r, channel, fmt.Errorf("could not send webhook: %s", er)) } @@ -650,9 +650,8 @@ func buildPayloads(msg courier.Msg, h *handler, clog *courier.ChannelLog) ([]int textAsCaption := false - // do we have a template? - templating, err := h.getTemplate(msg) - if templating != nil || len(msg.Attachments()) == 0 { + if len(msg.Attachments()) > 0 { + for attachmentCount, attachment := range msg.Attachments() { mimeType, mediaURL := handlers.SplitAttachment(attachment) mediaID, err := h.fetchMediaID(msg, mimeType, mediaURL, clog) @@ -820,6 +819,7 @@ func buildPayloads(msg courier.Msg, h *handler, clog *courier.ChannelLog) ([]int } payloads = append(payloads, payload) } else { + payload := templatePayload{ To: msg.URN().Path(), Type: "template", @@ -836,58 +836,6 @@ func buildPayloads(msg courier.Msg, h *handler, clog *courier.ChannelLog) ([]int } payload.Template.Components = append(payload.Template.Components, *component) - if len(msg.Attachments()) > 0 { - - header := &Component{Type: "header"} - - for _, attachment := range msg.Attachments() { - - mimeType, mediaURL := handlers.SplitAttachment(attachment) - mediaID, mediaLogs, err := h.fetchMediaID(msg, mimeType, mediaURL) - if len(mediaLogs) > 0 { - logs = append(logs, mediaLogs...) - } - if err != nil { - logrus.WithField("channel_uuid", msg.Channel().UUID().String()).WithError(err).Error("error while uploading media to whatsapp") - } - fileURL := mediaURL - if err != nil && mediaID != "" { - mediaURL = "" - } - if strings.HasPrefix(mimeType, "image") { - image := &mmtImage{ - Link: mediaURL, - } - header.Parameters = append(header.Parameters, Param{Type: "image", Image: image}) - payload.Template.Components = append(payload.Template.Components, *header) - } else if strings.HasPrefix(mimeType, "application") { - - filename, err := utils.BasePathForURL(fileURL) - if err != nil { - logrus.WithField("channel_uuid", msg.Channel().UUID().String()).WithError(err).Error("Error while parsing the media URL") - } - - document := &mmtDocument{ - Link: mediaURL, - Filename: filename, - } - header.Parameters = append(header.Parameters, Param{Type: "document", Document: document}) - payload.Template.Components = append(payload.Template.Components, *header) - } else if strings.HasPrefix(mimeType, "video") { - video := &mmtVideo{ - Link: mediaURL, - } - header.Parameters = append(header.Parameters, Param{Type: "video", Video: video}) - payload.Template.Components = append(payload.Template.Components, *header) - } else { - duration := time.Since(start) - err = fmt.Errorf("unknown attachment mime type: %s", mimeType) - attachmentLogs := []*courier.ChannelLog{courier.NewChannelLogFromError("Error sending message", msg.Channel(), msg.ID(), duration, err)} - logs = append(logs, attachmentLogs...) - break - } - } - } payloads = append(payloads, payload) } } else { @@ -984,152 +932,6 @@ func buildPayloads(msg courier.Msg, h *handler, clog *courier.ChannelLog) ([]int } } } - } else { - - if len(msg.Attachments()) > 0 { - for attachmentCount, attachment := range msg.Attachments() { - - mimeType, mediaURL := handlers.SplitAttachment(attachment) - mediaID, mediaLogs, err := h.fetchMediaID(msg, mimeType, mediaURL) - if len(mediaLogs) > 0 { - logs = append(logs, mediaLogs...) - } - if err != nil { - logrus.WithField("channel_uuid", msg.Channel().UUID().String()).WithError(err).Error("error while uploading media to whatsapp") - } - fileURL := mediaURL - if err == nil && mediaID != "" { - mediaURL = "" - } - mediaPayload := &mediaObject{ID: mediaID, Link: mediaURL} - if strings.HasPrefix(mimeType, "audio") { - payload := mtAudioPayload{ - To: msg.URN().Path(), - Type: "audio", - } - payload.Audio = mediaPayload - payloads = append(payloads, payload) - } else if strings.HasPrefix(mimeType, "application") { - payload := mtDocumentPayload{ - To: msg.URN().Path(), - Type: "document", - } - if attachmentCount == 0 && !isInteractiveMsg { - mediaPayload.Caption = msg.Text() - textAsCaption = true - } - mediaPayload.Filename, err = utils.BasePathForURL(fileURL) - // Logging error - if err != nil { - logrus.WithField("channel_uuid", msg.Channel().UUID().String()).WithError(err).Error("Error while parsing the media URL") - } - payload.Document = mediaPayload - payloads = append(payloads, payload) - } else if strings.HasPrefix(mimeType, "image") { - payload := mtImagePayload{ - To: msg.URN().Path(), - Type: "image", - } - if attachmentCount == 0 && !isInteractiveMsg { - mediaPayload.Caption = msg.Text() - textAsCaption = true - } - payload.Image = mediaPayload - payloads = append(payloads, payload) - } else if strings.HasPrefix(mimeType, "video") { - payload := mtVideoPayload{ - To: msg.URN().Path(), - Type: "video", - } - if attachmentCount == 0 && !isInteractiveMsg { - mediaPayload.Caption = msg.Text() - textAsCaption = true - } - payload.Video = mediaPayload - payloads = append(payloads, payload) - } else { - duration := time.Since(start) - err = fmt.Errorf("unknown attachment mime type: %s", mimeType) - attachmentLogs := []*courier.ChannelLog{courier.NewChannelLogFromError("Error sending message", msg.Channel(), msg.ID(), duration, err)} - logs = append(logs, attachmentLogs...) - break - } - } - - if !textAsCaption && !isInteractiveMsg { - for _, part := range parts { - - //check if you have a link - var payload mtTextPayload - if strings.Contains(part, "https://") || strings.Contains(part, "http://") { - payload = mtTextPayload{ - To: msg.URN().Path(), - Type: "text", - PreviewURL: true, - } - } else { - payload = mtTextPayload{ - To: msg.URN().Path(), - Type: "text", - } - } - payload.Text.Body = part - payloads = append(payloads, payload) - } - } - - if isInteractiveMsg { - for i, part := range parts { - if i < (len(parts) - 1) { //if split into more than one message, the first parts will be text and the last interactive - payload := mtTextPayload{ - To: msg.URN().Path(), - Type: "text", - } - payload.Text.Body = part - payloads = append(payloads, payload) - - } else { - payload := mtInteractivePayload{ - To: msg.URN().Path(), - Type: "interactive", - } - - // up to 3 qrs the interactive message will be button type, otherwise it will be list - if len(qrs) <= 3 { - payload.Interactive.Type = "button" - payload.Interactive.Body.Text = part - btns := make([]mtButton, len(qrs)) - for i, qr := range qrs { - btns[i] = mtButton{ - Type: "reply", - } - btns[i].Reply.ID = fmt.Sprint(i) - btns[i].Reply.Title = qr - } - payload.Interactive.Action.Buttons = btns - payloads = append(payloads, payload) - } else { - payload.Interactive.Type = "list" - payload.Interactive.Body.Text = part - payload.Interactive.Action.Button = "Menu" - section := mtSection{ - Rows: make([]mtSectionRow, len(qrs)), - } - for i, qr := range qrs { - section.Rows[i] = mtSectionRow{ - ID: fmt.Sprint(i), - Title: qr, - } - } - payload.Interactive.Action.Sections = []mtSection{ - section, - } - payloads = append(payloads, payload) - } - } - } - } - } } return payloads, err } @@ -1183,10 +985,10 @@ func (h *handler) fetchMediaID(msg courier.Msg, mimeType, mediaURL string, clog return "", errors.Wrapf(err, "error building request to media endpoint") } setWhatsAppAuthHeader(&req.Header, msg.Channel()) - mtype := http.DetectContentType(rr.Body) + mtype := http.DetectContentType(respBody) if mtype != mimeType || mtype == "application/octet-stream" || mtype == "application/zip" { - mimeT := mimetype.Detect(rr.Body) + mimeT := mimetype.Detect(respBody) req.Header.Add("Content-Type", mimeT.String()) } else { req.Header.Add("Content-Type", mtype) diff --git a/server.go b/server.go index 441a5eae8..9aa08d553 100644 --- a/server.go +++ b/server.go @@ -20,7 +20,6 @@ import ( "github.com/nyaruka/gocommon/analytics" "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/jsonx" - "github.com/nyaruka/librato" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) diff --git a/test/msg.go b/test/msg.go index 7ab7b76b7..f9354be9b 100644 --- a/test/msg.go +++ b/test/msg.go @@ -25,6 +25,7 @@ type mockMsg struct { metadata json.RawMessage alreadyWritten bool isResend bool + textLanguage string flow *courier.FlowReference @@ -76,6 +77,7 @@ func (m *mockMsg) Topic() string { return m.topic } func (m *mockMsg) ResponseToExternalID() string { return m.responseToExternalID } func (m *mockMsg) Metadata() json.RawMessage { return m.metadata } func (m *mockMsg) IsResend() bool { return m.isResend } +func (m *mockMsg) TextLanguage() string { return m.textLanguage } func (m *mockMsg) ReceivedOn() *time.Time { return m.receivedOn } func (m *mockMsg) SentOn() *time.Time { return m.sentOn } From 05632c297b9ae4a03f5591dee807be7b85efbc26 Mon Sep 17 00:00:00 2001 From: Robi9 Date: Wed, 27 Dec 2023 15:00:21 -0300 Subject: [PATCH 291/294] update gocommon --- go.mod | 4 ++-- go.sum | 4 ++-- handlers/facebookapp/facebookapp.go | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index a2c30eb8a..409334fed 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,6 @@ require ( github.com/gabriel-vasile/mimetype v1.4.1 github.com/golang-jwt/jwt/v4 v4.4.1 github.com/lestrrat-go/jwx v1.2.25 - github.com/nyaruka/librato v1.0.0 gopkg.in/go-playground/assert.v1 v1.2.1 ) @@ -60,6 +59,7 @@ require ( github.com/lestrrat-go/option v1.0.0 // indirect github.com/naoina/go-stringutil v0.1.0 // indirect github.com/naoina/toml v0.1.1 // indirect + github.com/nyaruka/librato v1.0.0 // indirect github.com/nyaruka/phonenumbers v1.1.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect @@ -71,4 +71,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -//replace github.com/nyaruka/gocommon => github.com/Ilhasoft/gocommon v1.22.2-weni +replace github.com/nyaruka/gocommon => github.com/Ilhasoft/gocommon v1.33.1-weni diff --git a/go.sum b/go.sum index 219d6f77b..302d80e34 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/Ilhasoft/gocommon v1.33.1-weni h1:3so8jFApBQpy+DdtyZzGvxTyrV2wy40u8C83BzkZ/Rg= +github.com/Ilhasoft/gocommon v1.33.1-weni/go.mod h1:gusIA2aNC8EPB3ozlP4O0PaBiHUNq5+f1peRNvcn0DI= github.com/antchfx/xmlquery v1.3.12 h1:6TMGpdjpO/P8VhjnaYPXuqT3qyJ/VsqoyNTmJzNBTQ4= github.com/antchfx/xmlquery v1.3.12/go.mod h1:3w2RvQvTz+DaT5fSgsELkSJcdNgkmg6vuXDEuhdwsPQ= github.com/antchfx/xpath v1.2.1 h1:qhp4EW6aCOVr5XIkT+l6LJ9ck/JsUH/yyauNgTQkBF8= @@ -95,8 +97,6 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.33.1 h1:RUy1O5Ly4tAaQDDpahds8z+4uewwsXg6SNCH0hYm7pE= -github.com/nyaruka/gocommon v1.33.1/go.mod h1:gusIA2aNC8EPB3ozlP4O0PaBiHUNq5+f1peRNvcn0DI= github.com/nyaruka/librato v1.0.0 h1:Vznj9WCeC1yZXbBYyYp40KnbmXLbEkjKmHesV/v2SR0= github.com/nyaruka/librato v1.0.0/go.mod h1:pkRNLFhFurOz0QqBz6/DuTFhHHxAubWxs4Jx+J7yUgg= github.com/nyaruka/null v1.2.0 h1:uEbkyy4Z+zPB2Pr3ryQh/0N2965I9kEsXq/cGpyJ7PA= diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index eb35a1253..2798daaba 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -441,7 +441,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h events, data, err = h.processCloudWhatsAppPayload(ctx, channel, payload, w, r, clog) webhook := channel.ConfigForKey("webhook", nil) if webhook != nil { - er := handlers.SendWebhooks(channel, r, webhook) + er := handlers.SendWebhooks(channel, r, webhook, clog) if er != nil { courier.LogRequestError(r, channel, fmt.Errorf("could not send webhook: %s", er)) } From b4c2161d26dca497c7b4afa90602491a6303d3c6 Mon Sep 17 00:00:00 2001 From: Robi9 Date: Wed, 27 Dec 2023 17:54:36 -0300 Subject: [PATCH 292/294] Fix facebookapp test --- config.go | 7 ++++--- handlers/facebookapp/facebookapp.go | 2 +- handlers/facebookapp/facebookapp_test.go | 6 +++--- handlers/test.go | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/config.go b/config.go index cf5a1fa3e..a6030ce4d 100644 --- a/config.go +++ b/config.go @@ -69,9 +69,10 @@ func NewConfig() *Config { S3DisableSSL: false, S3ForcePathStyle: false, - FacebookApplicationSecret: "missing_facebook_app_secret", - FacebookWebhookSecret: "missing_facebook_webhook_secret", - WhatsappAdminSystemUserToken: "missing_whatsapp_admin_system_user_token", + FacebookApplicationSecret: "missing_facebook_app_secret", + FacebookWebhookSecret: "missing_facebook_webhook_secret", + WhatsappAdminSystemUserToken: "missing_whatsapp_admin_system_user_token", + WhatsappCloudApplicationSecret: "missing_whatsapp_cloud_app_secret", MaxWorkers: 32, LogLevel: "error", diff --git a/handlers/facebookapp/facebookapp.go b/handlers/facebookapp/facebookapp.go index 2798daaba..512a508a8 100644 --- a/handlers/facebookapp/facebookapp.go +++ b/handlers/facebookapp/facebookapp.go @@ -1666,7 +1666,7 @@ func (h *handler) sendCloudAPIWhatsappMsg(ctx context.Context, msg courier.Msg, } // if payload.contacts[0].wa_id != payload.contacts[0].input | to fix cases with 9 extra - if len(respPayload.Contacts) > 0 && respPayload.Contacts[0].WaID != msg.URN().Path() { + if respPayload != nil && len(respPayload.Contacts) > 0 && respPayload.Contacts[0].WaID != msg.URN().Path() { if !hasNewURN { toUpdateURN, err := urns.NewWhatsAppURN(respPayload.Contacts[0].WaID) if err != nil { diff --git a/handlers/facebookapp/facebookapp_test.go b/handlers/facebookapp/facebookapp_test.go index d15e392f0..e6f5538fc 100644 --- a/handlers/facebookapp/facebookapp_test.go +++ b/handlers/facebookapp/facebookapp_test.go @@ -1262,7 +1262,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, MockResponseStatus: 201, - ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"document","document":{"link":"https://foo.bar/document.pdf","caption":"document caption"}}`, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"document","document":{"link":"https://foo.bar/document.pdf","caption":"document caption","filename":"document.pdf"}}`, ExpectedRequestPath: "/12345_ID/messages", ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", @@ -1303,7 +1303,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MsgMetadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "language": "eng", "variables": ["Chef", "tomorrow"]}}`), MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, MockResponseStatus: 200, - ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"template","template":{"name":"revive_issue","language":{"policy":"deterministic","code":"en"},"components":[{"type":"body","sub_type":"","index":"","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"template","template":{"name":"revive_issue","language":{"policy":"deterministic","code":"en"},"components":[{"type":"body","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, SendPrep: setSendURL, }, { @@ -1313,7 +1313,7 @@ var SendTestCasesWAC = []ChannelSendTestCase{ MsgMetadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "language": "eng", "country": "US", "variables": ["Chef", "tomorrow"]}}`), MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, MockResponseStatus: 200, - ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"template","template":{"name":"revive_issue","language":{"policy":"deterministic","code":"en_US"},"components":[{"type":"body","sub_type":"","index":"","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"template","template":{"name":"revive_issue","language":{"policy":"deterministic","code":"en_US"},"components":[{"type":"body","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, ExpectedMsgStatus: "W", ExpectedExternalID: "157b5e14568e8", SendPrep: setSendURL, diff --git a/handlers/test.go b/handlers/test.go index d476f61a7..2ed86ed18 100644 --- a/handlers/test.go +++ b/handlers/test.go @@ -159,7 +159,7 @@ func newServer(backend courier.Backend) courier.Server { config.FacebookWebhookSecret = "fb_webhook_secret" config.FacebookApplicationSecret = "fb_app_secret" config.WhatsappCloudWebhookSecret = "wac_webhook_secret" - config.WhatsappCloudApplicationSecret = "wac_app_secret" + config.WhatsappCloudApplicationSecret = "fb_app_secret" config.WhatsappAdminSystemUserToken = "wac_admin_system_user_token" return courier.NewServerWithLogger(config, backend, logger) From 0647d1c89cf6fb45f885a6a7a21bb1b01404f7e4 Mon Sep 17 00:00:00 2001 From: Robi9 Date: Wed, 27 Dec 2023 18:29:10 -0300 Subject: [PATCH 293/294] Fix Teams tests --- handlers/teams/teams.go | 56 ++++++++++++--------------- handlers/teams/teams_test.go | 59 ++++++++++++++++++++--------- handlers/weniwebchat/weniwebchat.go | 2 +- 3 files changed, 68 insertions(+), 49 deletions(-) diff --git a/handlers/teams/teams.go b/handlers/teams/teams.go index a10073396..862ac9db4 100644 --- a/handlers/teams/teams.go +++ b/handlers/teams/teams.go @@ -163,7 +163,9 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } - serviceURL := payload.ServiceUrl + path := strings.Split(payload.ServiceURL, "//") + serviceURL := path[1] + var urn urns.URN // the list of events we deal with @@ -178,9 +180,9 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } if payload.Type == "message" { - sender := payload.Conversation.ID + sender := strings.Split(payload.Conversation.ID, "a:") - urn, err = urns.NewTeamsURN(sender + ":serviceURL:" + serviceURL) + urn, err = urns.NewTeamsURN(sender[1] + ":" + path[1]) if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } @@ -189,12 +191,12 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h attachmentURLs := make([]string, 0, 2) for _, att := range payload.Attachments { - if att.ContentType != "" && att.ContentUrl != "" { - attachmentURLs = append(attachmentURLs, att.ContentUrl) + if att.ContentType != "" && att.ContentURL != "" { + attachmentURLs = append(attachmentURLs, att.ContentURL) } } - ev := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithExternalID(payload.Id).WithReceivedOn(date) + ev := h.Backend().NewIncomingMsg(channel, urn, text, clog).WithExternalID(payload.ID).WithReceivedOn(date) event := h.Backend().CheckExternalIDSeen(ev) // add any attachment URL found @@ -220,11 +222,6 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, nil } - act := Activity{} - - act.Text = "Create Conversation" - act.Type = "message" - bot := ChannelAccount{} bot.ID = channel.StringConfigForKey("botID", "") @@ -233,21 +230,18 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h members := []ChannelAccount{} members = append(members, ChannelAccount{ID: userID, Role: payload.MembersAdded[0].Role}) - tenantID := channel.StringConfigForKey("tenantID", "") ConversationJson := &mtPayload{ - Activity: act, - Bot: bot, - Members: members, - IsGroup: false, - TenantId: tenantID, + Bot: bot, + Members: members, + IsGroup: false, } jsonBody, err := json.Marshal(ConversationJson) if err != nil { return nil, err } token := channel.StringConfigForKey(courier.ConfigAuthToken, "") - req, err := http.NewRequest(http.MethodPost, serviceURL+"/v3/conversations", bytes.NewReader(jsonBody)) + req, err := http.NewRequest(http.MethodPost, payload.ServiceURL+"/v3/conversations", bytes.NewReader(jsonBody)) if err != nil { return nil, err @@ -255,9 +249,9 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer "+token) - _, respBody, err := handlers.RequestHTTP(req, clog) - if err != nil { - return nil, err + resp, respBody, err := handlers.RequestHTTP(req, clog) + if err != nil || resp.StatusCode/100 != 2 { + return nil, errors.New("unable to look up contact data") } var body ConversationAccount @@ -266,8 +260,8 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h if err != nil { return nil, err } - - urn, err = urns.NewTeamsURN(body.ID + ":serviceURL:" + serviceURL) + conversationID := strings.Split(body.ID, "a:") + urn, err = urns.NewTeamsURN(conversationID[1] + ":" + serviceURL) if err != nil { return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } @@ -318,22 +312,22 @@ type ConversationAccount struct { AadObjectId string `json:"aadObjectId"` } -type Attachment struct { +type mtAttachment struct { ContentType string `json:"contentType"` - ContentUrl string `json:"contentUrl"` + ContentURL string `json:"contentUrl"` Name string `json:"name,omitempty"` } type Activity struct { Action string `json:"action,omitempty"` - Attachments []Attachment `json:"attachments,omitempty"` - ChannelId string `json:"channelId,omitempty"` + Attachments []mtAttachment `json:"attachments,omitempty"` + ChannelID string `json:"channelId,omitempty"` Conversation ConversationAccount `json:"conversation,omitempty"` - Id string `json:"id,omitempty"` + ID string `json:"id,omitempty"` MembersAdded []ChannelAccount `json:"membersAdded,omitempty"` Name string `json:"name,omitempty"` Recipient ChannelAccount `json:"recipient,omitempty"` - ServiceUrl string `json:"serviceUrl,omitempty"` + ServiceURL string `json:"serviceUrl,omitempty"` Text string `json:"text"` Type string `json:"type"` Timestamp string `json:"timestamp,omitempty"` @@ -361,7 +355,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann if err != nil { logrus.WithField("channel_uuid", msg.Channel().UUID().String()).WithError(err).Error("Error while parsing the media URL") } - payload.Attachments = append(payload.Attachments, Attachment{attType, attURL, filename}) + payload.Attachments = append(payload.Attachments, mtAttachment{attType, attURL, filename}) } if msg.Text() != "" { @@ -412,7 +406,7 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn req.Header.Set("Authorization", "Bearer "+accessToken) resp, respBody, err := handlers.RequestHTTP(req, clog) if err != nil { - return nil, fmt.Errorf("unable to look up contact data:%s\n%s", err, resp) + return nil, fmt.Errorf("unable to look up contact data:%v\n%v", err, resp) } // read our first and last name diff --git a/handlers/teams/teams_test.go b/handlers/teams/teams_test.go index 872661379..bdd61c103 100644 --- a/handlers/teams/teams_test.go +++ b/handlers/teams/teams_test.go @@ -2,12 +2,15 @@ package teams import ( "context" + "io" + "log" "net/http" "net/http/httptest" "strings" "testing" "time" + "github.com/buger/jsonparser" "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" @@ -127,7 +130,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedRespStatus: 200, ExpectedBodyContains: "Handled", ExpectedMsgText: Sp("Hello World"), - ExpectedURN: "teams:a:2811:serviceURL:https://smba.trafficmanager.net/br/", + ExpectedURN: "teams:2811:smba.trafficmanager.net/br/", ExpectedExternalID: "56834", ExpectedDate: time.Date(2022, 6, 6, 16, 51, 00, 0000000, time.UTC), Headers: map[string]string{"Authorization": "Bearer " + access_token}, @@ -141,7 +144,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedBodyContains: "Handled", ExpectedMsgText: Sp("Hello World"), ExpectedAttachments: []string{"https://image-url/foo.png"}, - ExpectedURN: "teams:a:2811:serviceURL:https://smba.trafficmanager.net/br/", + ExpectedURN: "teams:2811:smba.trafficmanager.net/br/", ExpectedExternalID: "56834", ExpectedDate: time.Date(2022, 6, 6, 16, 51, 00, 0000000, time.UTC), Headers: map[string]string{"Authorization": "Bearer " + access_token}, @@ -155,7 +158,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedBodyContains: "Handled", ExpectedMsgText: Sp("Hello World"), ExpectedAttachments: []string{"https://video-url/foo.mp4"}, - ExpectedURN: "teams:a:2811:serviceURL:https://smba.trafficmanager.net/br/", + ExpectedURN: "teams:2811:smba.trafficmanager.net/br/", ExpectedExternalID: "56834", ExpectedDate: time.Date(2022, 6, 6, 16, 51, 00, 0000000, time.UTC), Headers: map[string]string{"Authorization": "Bearer " + access_token}, @@ -169,7 +172,7 @@ var testCases = []ChannelHandleTestCase{ ExpectedBodyContains: "Handled", ExpectedMsgText: Sp("Hello World"), ExpectedAttachments: []string{"https://document-url/foo.pdf"}, - ExpectedURN: "teams:a:2811:serviceURL:https://smba.trafficmanager.net/br/", + ExpectedURN: "teams:2811:smba.trafficmanager.net/br/", ExpectedExternalID: "56834", ExpectedDate: time.Date(2022, 6, 6, 16, 51, 00, 0000000, time.UTC), Headers: map[string]string{"Authorization": "Bearer " + access_token}, @@ -221,6 +224,7 @@ func buildMockTeams() *httptest.Server { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { accessToken := r.Header.Get("Authorization") tokenH := strings.Replace(accessToken, "Bearer ", "", 1) + // payload := r.GetBody defer r.Body.Close() // invalid auth token @@ -234,6 +238,18 @@ func buildMockTeams() *httptest.Server { } if r.URL.Path == "/v3/conversations/a:2022/activities" { + byteBody, err := io.ReadAll(r.Body) + if err != nil { + log.Fatal(err) + } + text, err := jsonparser.GetString(byteBody, "text") + if err != nil { + log.Fatal(err) + } + if text == "Error" { + w.Header().Add("Content-Type", "application/json") + w.Write([]byte(`{"is_error": true}`)) + } w.Header().Add("Content-Type", "application/json") w.Write([]byte(`{"id":"1234567890"}`)) } @@ -262,32 +278,37 @@ var defaultSendTestCases = []ChannelSendTestCase{ { Label: "Plain Send", MsgText: "Simple Message", - MsgURN: "teams:a:2022:serviceURL:https://smba.trafficmanager.net/br/", + MsgURN: "teams:2022:https://smba.trafficmanager.net/br/", ExpectedMsgStatus: "W", ExpectedExternalID: "1234567890", MockResponseBody: `{id:"1234567890"}`, MockResponseStatus: 200, }, {Label: "Send Photo", - MsgURN: "teams:a:2022:serviceURL:https://smba.trafficmanager.net/br/", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MsgURN: "teams:2022:https://smba.trafficmanager.net/br/", MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, ExpectedMsgStatus: "W", ExpectedExternalID: "1234567890", MockResponseBody: `{"id": "1234567890"}`, MockResponseStatus: 200, }, {Label: "Send Video", - MsgURN: "teams:a:2022:serviceURL:https://smba.trafficmanager.net/br/", MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, + MsgURN: "teams:2022:https://smba.trafficmanager.net/br/", MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, ExpectedMsgStatus: "W", ExpectedExternalID: "1234567890", MockResponseBody: `{"id": "1234567890"}`, MockResponseStatus: 200, }, {Label: "Send Document", - MsgURN: "teams:a:2022:serviceURL:https://smba.trafficmanager.net/br/", MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, + MsgURN: "teams:2022:https://smba.trafficmanager.net/br/", MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, ExpectedMsgStatus: "W", ExpectedExternalID: "1234567890", MockResponseBody: `{"id": "1234567890"}`, MockResponseStatus: 200, }, + {Label: "ID Error", + MsgText: "Error", MsgURN: "teams:2022:smba.trafficmanager.net/br/", + ExpectedMsgStatus: "E", + MockResponseBody: `{"is_error": true}`, MockResponseStatus: 200, + }, } func newSendTestCases(testSendCases []ChannelSendTestCase, url string) []ChannelSendTestCase { var newtestSendCases []ChannelSendTestCase for _, tc := range testSendCases { - spTC := strings.Split(tc.MsgURN, ":serviceURL:") - newURN := spTC[0] + ":serviceURL:" + url + "/" + spTC := strings.Split(tc.MsgURN, ":") + newURN := spTC[0] + ":" + spTC[1] + ":" + url + "/" tc.MsgURN = newURN newtestSendCases = append(newtestSendCases, tc) } @@ -299,23 +320,27 @@ func TestSending(t *testing.T) { map[string]interface{}{courier.ConfigAuthToken: access_token, "tenantID": "cba321", "botID": "0123", "appID": "1596"}) serviceTM := buildMockTeams() - newSendTestCases := newSendTestCases(defaultSendTestCases, serviceTM.URL) + url := strings.Split(serviceTM.URL, "http://") + newSendTestCases := newSendTestCases(defaultSendTestCases, url[1]) RunChannelSendTestCases(t, defaultChannel, newHandler(), newSendTestCases, nil, nil) serviceTM.Close() } func TestDescribe(t *testing.T) { server := buildMockTeams() - clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], nil) + url := strings.Split(server.URL, "http://") + + channel := testChannels[0] handler := newHandler().(courier.URNDescriber) + logger := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, nil) tcs := []struct { - urn urns.URN - metadata map[string]string - }{{urns.URN("teams:a:2022:serviceURL:" + string(server.URL) + "/"), map[string]string{"name": "John Doe"}}} + urn urns.URN + expectedMetadata map[string]string + }{{urns.URN("teams:2022:" + string(url[1]) + "/"), map[string]string{"name": "John Doe"}}} for _, tc := range tcs { - metadata, _ := handler.DescribeURN(context.Background(), testChannels[0], tc.urn, clog) - assert.Equal(t, metadata, tc.metadata) + metadata, _ := handler.DescribeURN(context.Background(), testChannels[0], tc.urn, logger) + assert.Equal(t, metadata, tc.expectedMetadata) } server.Close() } diff --git a/handlers/weniwebchat/weniwebchat.go b/handlers/weniwebchat/weniwebchat.go index 92c9d38fb..1378fe763 100644 --- a/handlers/weniwebchat/weniwebchat.go +++ b/handlers/weniwebchat/weniwebchat.go @@ -161,7 +161,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann MediaURL: attachmentURL, } } else { - logrus.WithField("channel_uuid", msg.Channel().UUID().String()).Error("unknown attachment mime type: %s", mimeType) + logrus.WithField("channel_uuid", msg.Channel().UUID().String()).Error("unknown attachment mime type: ", mimeType) status.SetStatus(courier.MsgFailed) break attachmentsLoop } From d1480bd7efda44c9901f71fac3f1d251fe8b2f1b Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Wed, 27 Dec 2023 19:54:24 -0300 Subject: [PATCH 294/294] update weni-changelog.md for 1.5.2-courier-7.5.64 --- WENI-CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/WENI-CHANGELOG.md b/WENI-CHANGELOG.md index 6d273cfd3..f32336533 100644 --- a/WENI-CHANGELOG.md +++ b/WENI-CHANGELOG.md @@ -1,3 +1,7 @@ +1.5.2-courier-7.5.64 +---------- + * Update to v7.5.64 + 1.5.2-courier-7.4.0 ---------- * Add module to send webhooks for WAC and WA