From 760340f1d06198a5520b0e9d3db39428eaeea554 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 21 Feb 2024 17:23:58 +0200 Subject: [PATCH 01/15] Use MockResponses and ExpectedRequests in I2 tests --- handlers/i2sms/handler_test.go | 103 ++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 35 deletions(-) diff --git a/handlers/i2sms/handler_test.go b/handlers/i2sms/handler_test.go index c328ce934..949bffecc 100644 --- a/handlers/i2sms/handler_test.go +++ b/handlers/i2sms/handler_test.go @@ -1,7 +1,6 @@ package i2sms import ( - "net/http/httptest" "net/url" "testing" @@ -46,18 +45,17 @@ func BenchmarkHandler(b *testing.B) { RunChannelBenchmarks(b, testChannels, newHandler(), testCases) } -func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.MsgOut) { - sendURL = s.URL -} - var defaultSendTestCases = []OutgoingTestCase{ { - 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, + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponses: map[string][]*httpx.MockResponse{ + "https://mx2.i2sms.net/mxapi.php": { + httpx.NewMockResponse(200, nil, []byte(`{"result":{"session_id":"5b8fc97d58795484819426"}, "error_code": "00", "error_desc": "Success"}`)), + }, + }, ExpectedRequests: []ExpectedRequest{ { Form: url.Values{ @@ -70,36 +68,71 @@ var defaultSendTestCases = []OutgoingTestCase{ }, ExpectedMsgStatus: "W", ExpectedExtIDs: []string{"5b8fc97d58795484819426"}, - SendPrep: setSendURL, }, { - Label: "Invalid JSON", - MsgText: "Invalid XML", - MsgURN: "tel:+250788383383", - MockResponseBody: `not json`, - MockResponseStatus: 200, - ExpectedMsgStatus: "E", - ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseUnparseable("JSON")}, - SendPrep: setSendURL, + Label: "Invalid JSON", + MsgText: "Invalid XML", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "https://mx2.i2sms.net/mxapi.php": { + httpx.NewMockResponse(200, nil, []byte(`not json`)), + }, + }, + ExpectedRequests: []ExpectedRequest{ + { + Form: url.Values{ + "action": {"send_single"}, + "mobile": {"250788383383"}, + "message": {"Invalid XML"}, + "channel": {"hash123"}, + }, + }, + }, + ExpectedMsgStatus: "E", + ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseUnparseable("JSON")}, }, { - Label: "Error Response", - MsgText: "Error Response", - MsgURN: "tel:+250788383383", - MockResponseBody: `{"result":{}, "error_code": "10", "error_desc": "Failed"}`, - MockResponseStatus: 200, - ExpectedMsgStatus: "F", - ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseValueUnexpected("error_code", "00")}, - SendPrep: setSendURL, + Label: "Error Response", + MsgText: "Error Response", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "https://mx2.i2sms.net/mxapi.php": { + httpx.NewMockResponse(200, nil, []byte(`{"result":{}, "error_code": "10", "error_desc": "Failed"}`)), + }, + }, + ExpectedRequests: []ExpectedRequest{ + { + Form: url.Values{ + "action": {"send_single"}, + "mobile": {"250788383383"}, + "message": {"Error Response"}, + "channel": {"hash123"}, + }, + }, + }, + ExpectedMsgStatus: "F", + ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseValueUnexpected("error_code", "00")}, }, { - Label: "Error Sending", - MsgText: "Error Message", - MsgURN: "tel:+250788383383", - MockResponseBody: `Bad Gateway`, - MockResponseStatus: 501, - ExpectedMsgStatus: "E", - SendPrep: setSendURL, + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "https://mx2.i2sms.net/mxapi.php": { + httpx.NewMockResponse(501, nil, []byte(`Bad Gateway`)), + }, + }, + ExpectedRequests: []ExpectedRequest{ + { + Form: url.Values{ + "action": {"send_single"}, + "mobile": {"250788383383"}, + "message": {"Error Message"}, + "channel": {"hash123"}, + }, + }, + }, + ExpectedMsgStatus: "E", }, } From dfdd250f06167df80982d14f875fae26dbe4a60e Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 21 Feb 2024 17:33:02 +0200 Subject: [PATCH 02/15] Use MockResponses and ExpectedRequests in IB tests --- handlers/infobip/handler_test.go | 182 ++++++++++++++++++------------- 1 file changed, 105 insertions(+), 77 deletions(-) diff --git a/handlers/infobip/handler_test.go b/handlers/infobip/handler_test.go index 034899d27..4e93c9dc2 100644 --- a/handlers/infobip/handler_test.go +++ b/handlers/infobip/handler_test.go @@ -1,7 +1,6 @@ package infobip import ( - "net/http/httptest" "testing" "time" @@ -297,108 +296,137 @@ 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.MsgOut) { - sendURL = s.URL -} - var defaultSendTestCases = []OutgoingTestCase{ { - Label: "Plain Send", - MsgText: "Simple Message", - MsgURN: "tel:+250788383383", + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "https://api.infobip.com/sms/1/text/advanced": { + httpx.NewMockResponse(200, nil, []byte(`{"messages":[{"status":{"groupId": 1}, "messageId": "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"}]}`, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"12345"}, - SendPrep: setSendURL, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", + }, + Body: `{"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", + ExpectedExtIDs: []string{"12345"}, }, { - Label: "Unicode Send", - MsgText: "☺", - MsgURN: "tel:+250788383383", + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "https://api.infobip.com/sms/1/text/advanced": { + httpx.NewMockResponse(200, nil, []byte(`{"messages":[{"status":{"groupId": 1}}}`)), + }, + }, 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"}]}`, - ExpectedMsgStatus: "W", - SendPrep: setSendURL, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", + }, + Body: `{"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"}]}`, + }}, + ExpectedMsgStatus: "W", }, { - Label: "Send Attachment", - MsgText: "My pic!", - MsgURN: "tel:+250788383383", - MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponses: map[string][]*httpx.MockResponse{ + "https://api.infobip.com/sms/1/text/advanced": { + httpx.NewMockResponse(200, nil, []byte(`{"messages":[{"status":{"groupId": 1}}}`)), + }, + }, 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"}]}`, - ExpectedMsgStatus: "W", - SendPrep: setSendURL, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", + }, + Body: `{"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"}]}`, + }}, + ExpectedMsgStatus: "W", }, { - 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=", + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "https://api.infobip.com/sms/1/text/advanced": { + httpx.NewMockResponse(401, nil, []byte(`{ "error": "failed" }`)), + }, }, - 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"}]}`, - ExpectedMsgStatus: "E", - SendPrep: setSendURL, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", + }, + Body: `{"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"}]}`, + }}, + ExpectedMsgStatus: "E", }, { - Label: "Error groupId", - MsgText: "Simple Message", - MsgURN: "tel:+250788383383", + Label: "Error groupId", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "https://api.infobip.com/sms/1/text/advanced": { + httpx.NewMockResponse(200, nil, []byte(`{"messages":[{"status":{"groupId": 2}}}`)), + }, + }, 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"}]}`, - ExpectedMsgStatus: "E", - ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseValueUnexpected("groupId", "1", "3")}, - SendPrep: setSendURL, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", + }, + Body: `{"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", + ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseValueUnexpected("groupId", "1", "3")}, }, } var transSendTestCases = []OutgoingTestCase{ { - Label: "Plain Send", - MsgText: "Simple Message", - MsgURN: "tel:+250788383383", + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "https://api.infobip.com/sms/1/text/advanced": { + httpx.NewMockResponse(200, nil, []byte(`{"messages":[{"status":{"groupId": 1}, "messageId": "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","transliteration":"COLOMBIAN"}]}`, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"12345"}, - SendPrep: setSendURL, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=", + }, + Body: `{"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"}]}`, + }}, + ExpectedMsgStatus: "W", + ExpectedExtIDs: []string{"12345"}, }, } From c4193070c82dbb2aca5ad74bdd632e2a8741ff22 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 21 Feb 2024 17:54:22 +0200 Subject: [PATCH 03/15] Use MockResponses and ExpectedRequests in JS tests --- handlers/jasmin/handler_test.go | 185 +++++++++++++++++++++----------- 1 file changed, 124 insertions(+), 61 deletions(-) diff --git a/handlers/jasmin/handler_test.go b/handlers/jasmin/handler_test.go index 783a9ac0e..dff7da8e9 100644 --- a/handlers/jasmin/handler_test.go +++ b/handlers/jasmin/handler_test.go @@ -2,12 +2,13 @@ package jasmin import ( "net/http" - "net/http/httptest" + "net/url" "testing" "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) const ( @@ -84,85 +85,147 @@ func BenchmarkHandler(b *testing.B) { RunChannelBenchmarks(b, testChannels, newHandler(), handleTestCases) } -// 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.MsgOut) { - c.(*test.MockChannel).SetConfig("send_url", s.URL) -} - var defaultSendTestCases = []OutgoingTestCase{ { - Label: "Plain Send", - MsgText: "Simple Message", - MsgURN: "tel:+250788383383", - MockResponseBody: `Success "External ID1"`, - MockResponseStatus: 200, - 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", + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/send*": { + httpx.NewMockResponse(200, nil, []byte(`Success "External ID1"`)), + }, }, + ExpectedRequests: []ExpectedRequest{{ + Params: url.Values{ + "content": {"Simple Message"}, + "to": {"250788383383"}, + "from": {"2020"}, + "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"}, + }, + }}, ExpectedExtIDs: []string{"External ID1"}, ExpectedMsgStatus: "W", - SendPrep: setSendURL, }, { - Label: "Unicode Send", - MsgText: "☺", - MockResponseBody: `Success "External ID1"`, - MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"content": "?"}, - ExpectedExtIDs: []string{"External ID1"}, - ExpectedMsgStatus: "W", - SendPrep: setSendURL, + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/send*": { + httpx.NewMockResponse(200, nil, []byte(`Success "External ID1"`)), + }, + }, + ExpectedRequests: []ExpectedRequest{{ + Params: url.Values{ + "content": {"?"}, + "to": {"250788383383"}, + "from": {"2020"}, + "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"}, + }, + }}, + ExpectedExtIDs: []string{"External ID1"}, + ExpectedMsgStatus: "W", }, { - Label: "Smart Encoding", - MsgText: "Fancy “Smart” Quotes", - MsgURN: "tel:+250788383383", - MockResponseBody: `Success "External ID1"`, - MockResponseStatus: 200, - ExpectedURLParams: map[string]string{"content": `Fancy "Smart" Quotes`}, - ExpectedExtIDs: []string{"External ID1"}, - ExpectedMsgStatus: "W", - SendPrep: setSendURL, + Label: "Smart Encoding", + MsgText: "Fancy “Smart” Quotes", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/send*": { + httpx.NewMockResponse(200, nil, []byte(`Success "External ID1"`)), + }, + }, + ExpectedRequests: []ExpectedRequest{{ + Params: url.Values{ + "content": {`Fancy "Smart" Quotes`}, + "to": {"250788383383"}, + "from": {"2020"}, + "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"}, + }, + }}, + ExpectedExtIDs: []string{"External ID1"}, + ExpectedMsgStatus: "W", }, { - 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"}, - ExpectedExtIDs: []string{"External ID1"}, - ExpectedMsgStatus: "W", - SendPrep: setSendURL, + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgHighPriority: true, + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/send*": { + httpx.NewMockResponse(200, nil, []byte(`Success "External ID1"`)), + }, + }, + ExpectedRequests: []ExpectedRequest{{ + Params: url.Values{ + "content": {"My pic!\nhttps://foo.bar/image.jpg"}, + "to": {"250788383383"}, + "from": {"2020"}, + "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"}, + }, + }}, + ExpectedExtIDs: []string{"External ID1"}, + ExpectedMsgStatus: "W", }, { - 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, + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MsgHighPriority: false, + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/send*": { + httpx.NewMockResponse(401, nil, []byte(`Failed Sending`)), + }, + }, + ExpectedRequests: []ExpectedRequest{{ + Params: url.Values{ + "content": {"Error Message"}, + "to": {"250788383383"}, + "from": {"2020"}, + "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: "E", }, } func TestOutgoing(t *testing.T) { var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "JS", "2020", "US", map[string]any{ - "password": "Password", - "username": "Username", + "password": "Password", + "username": "Username", + courier.ConfigSendURL: "http://example.com/send", }) RunOutgoingTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"Password"}, nil) From 6a199db543fd66811ab201494d85f36261c41c43 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 21 Feb 2024 18:00:37 +0200 Subject: [PATCH 04/15] Use MockResponses and ExpectedRequests in JC tests --- handlers/jiochat/handler_test.go | 114 +++++++++++++++++++------------ 1 file changed, 69 insertions(+), 45 deletions(-) diff --git a/handlers/jiochat/handler_test.go b/handlers/jiochat/handler_test.go index 82cf505b9..cd5825f94 100644 --- a/handlers/jiochat/handler_test.go +++ b/handlers/jiochat/handler_test.go @@ -344,62 +344,86 @@ func TestBuildAttachmentRequest(t *testing.T) { AssertChannelLogRedaction(t, clog, []string{"secret123"}) } -// setSendURL takes care of setting the sendURL to call -func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.MsgOut) { - sendURL = s.URL -} - var defaultSendTestCases = []OutgoingTestCase{ { - Label: "Plain Send", - MsgText: "Simple Message ☺", - MsgURN: "jiochat:12345", - MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Bearer ACCESS_TOKEN", + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "jiochat:12345", + MockResponses: map[string][]*httpx.MockResponse{ + "https://channels.jiochat.com/custom/custom_send.action": { + httpx.NewMockResponse(200, nil, []byte(``)), + }, }, - ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"Simple Message ☺"}}`, - ExpectedMsgStatus: "W", - SendPrep: setSendURL, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "Bearer ACCESS_TOKEN", + }, + Body: `{"msgtype":"text","touser":"12345","text":{"content":"Simple Message ☺"}}`, + }}, + ExpectedMsgStatus: "W", }, { - 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", - MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Bearer ACCESS_TOKEN", + 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", + MockResponses: map[string][]*httpx.MockResponse{ + "https://channels.jiochat.com/custom/custom_send.action": { + httpx.NewMockResponse(200, nil, []byte(``)), + httpx.NewMockResponse(200, nil, []byte(``)), + }, }, - ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"I need to keep adding more things to make it work"}}`, - ExpectedMsgStatus: "W", - SendPrep: setSendURL, + ExpectedRequests: []ExpectedRequest{ + { + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "Bearer ACCESS_TOKEN", + }, + Body: `{"msgtype":"text","touser":"12345","text":{"content":"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,"}}`, + }, + { + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "Bearer ACCESS_TOKEN", + }, + Body: `{"msgtype":"text","touser":"12345","text":{"content":"I need to keep adding more things to make it work"}}`, + }, + }, + ExpectedMsgStatus: "W", }, { - Label: "Send Attachment", - MsgText: "My pic!", - MsgURN: "jiochat:12345", - MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MockResponseStatus: 200, - ExpectedHeaders: map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Bearer ACCESS_TOKEN", + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "jiochat:12345", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponses: map[string][]*httpx.MockResponse{ + "https://channels.jiochat.com/custom/custom_send.action": { + httpx.NewMockResponse(200, nil, []byte(``)), + }, }, - ExpectedRequestBody: `{"msgtype":"text","touser":"12345","text":{"content":"My pic!\nhttps://foo.bar/image.jpg"}}`, - ExpectedMsgStatus: "W", - SendPrep: setSendURL, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "Bearer ACCESS_TOKEN", + }, + Body: `{"msgtype":"text","touser":"12345","text":{"content":"My pic!\nhttps://foo.bar/image.jpg"}}`, + }}, + ExpectedMsgStatus: "W", }, { - Label: "Error Sending", - MsgText: "Error Message", - MsgURN: "jiochat:12345", - MockResponseStatus: 401, - ExpectedMsgStatus: "E", - SendPrep: setSendURL, + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "jiochat:12345", + MockResponses: map[string][]*httpx.MockResponse{ + "https://channels.jiochat.com/custom/custom_send.action": { + httpx.NewMockResponse(401, nil, []byte(``)), + }, + }, + ExpectedMsgStatus: "E", }, } From e2a55a993c0f5a53462dd7ec0774955db480b06c Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 21 Feb 2024 18:06:02 +0200 Subject: [PATCH 05/15] Use MockResponses and ExpectedRequests in JCL tests --- handlers/justcall/handler_test.go | 117 +++++++++++++++++++----------- 1 file changed, 73 insertions(+), 44 deletions(-) diff --git a/handlers/justcall/handler_test.go b/handlers/justcall/handler_test.go index f6133cd3d..deb547abe 100644 --- a/handlers/justcall/handler_test.go +++ b/handlers/justcall/handler_test.go @@ -1,13 +1,13 @@ package justcall import ( - "net/http/httptest" "testing" "time" "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) var testChannels = []courier.Channel{ @@ -267,57 +267,86 @@ 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.MsgOut) { - sendURL = s.URL -} - var defaultSendTestCases = []OutgoingTestCase{ { - 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", + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "https://api.justcall.io/v1/texts/new": { + httpx.NewMockResponse(200, nil, []byte(`{"status":"success","message":"Text sent","id":12345}`)), + }, }, - ExpectedRequestBody: `{"from":"2020","to":"+250788383383","body":"Simple Message"}`, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"12345"}, - SendPrep: setSendURL, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "api_key:api_secret", + }, + Body: `{"from":"2020","to":"+250788383383","body":"Simple Message"}`, + }}, + ExpectedMsgStatus: "W", + ExpectedExtIDs: []string{"12345"}, }, { - 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", - ExpectedExtIDs: []string{"12345"}, - SendPrep: setSendURL}, + Label: "Send Document", + MsgText: "This is some text.", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, + MockResponses: map[string][]*httpx.MockResponse{ + "https://api.justcall.io/v1/texts/new": { + httpx.NewMockResponse(200, nil, []byte(`{"status":"success","message":"Text sent","id":12345}`)), + }, + }, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "api_key:api_secret", + }, + Body: `{"from":"2020","to":"+250788383383","body":"This is some text.","media_url":"https://foo.bar/document.pdf"}`, + }}, + ExpectedMsgStatus: "W", + ExpectedExtIDs: []string{"12345"}, + }, { - Label: "ID Error", - MsgText: "ID Error", - MsgURN: "tel:+250788383383", - MockResponseBody: `{ "status": "success" }`, - MockResponseStatus: 200, - ExpectedMsgStatus: "E", - ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("id")}, - SendPrep: setSendURL, + Label: "ID Error", + MsgText: "ID Error", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "https://api.justcall.io/v1/texts/new": { + httpx.NewMockResponse(200, nil, []byte(`{ "status": "success" }`)), + }, + }, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "api_key:api_secret", + }, + Body: `{"from":"2020","to":"+250788383383","body":"ID Error"}`, + }}, + ExpectedMsgStatus: "E", + ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("id")}, }, { - Label: "Error", - MsgText: "Error", - MsgURN: "tel:+250788383383", - MockResponseBody: `{ "status": "fail" }`, - MockResponseStatus: 403, - ExpectedMsgStatus: "E", - SendPrep: setSendURL, + Label: "Error", + MsgText: "Error", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "https://api.justcall.io/v1/texts/new": { + httpx.NewMockResponse(403, nil, []byte(`{ "status": "fail" }`)), + }, + }, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "api_key:api_secret", + }, + Body: `{"from":"2020","to":"+250788383383","body":"Error"}`, + }}, + ExpectedMsgStatus: "E", }, } From ad503f7bf58a8e95a52e9915b37804f00968c3ea Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 21 Feb 2024 18:37:00 +0200 Subject: [PATCH 06/15] Use MockResponses and ExpectedRequests in KN tests --- handlers/kannel/handler_test.go | 295 +++++++++++++++++++++----------- 1 file changed, 199 insertions(+), 96 deletions(-) diff --git a/handlers/kannel/handler_test.go b/handlers/kannel/handler_test.go index 0698849a8..7eac5dc37 100644 --- a/handlers/kannel/handler_test.go +++ b/handlers/kannel/handler_test.go @@ -1,13 +1,14 @@ package kannel import ( - "net/http/httptest" + "net/url" "testing" "time" "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) var testChannels = []courier.Channel{ @@ -128,131 +129,233 @@ func BenchmarkHandler(b *testing.B) { RunChannelBenchmarks(b, testChannels, newHandler(), handleTestCases) } -// 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.MsgOut) { - 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.MsgOut) { - c.(*test.MockChannel).SetConfig("send_url", s.URL+"?auth=foo") -} - var defaultSendTestCases = []OutgoingTestCase{ { - 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", + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MsgHighPriority: false, + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/send*": { + httpx.NewMockResponse(200, nil, []byte(`0: Accepted for delivery`)), + }, }, - SendPrep: setSendURL, + ExpectedMsgStatus: "W", + ExpectedRequests: []ExpectedRequest{{ + Params: url.Values{ + "text": {"Simple Message"}, + "to": {"+250788383383"}, + "from": {"2020"}, + "dlr-mask": {"27"}, + "dlr-url": {"https://localhost/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%d"}, + "username": {"Username"}, + "password": {"Password"}, + }, + }}, }, { - 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: "Unicode Send", + MsgText: "☺", + MsgURN: "tel:+250788383383", + MsgHighPriority: false, + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/send*": { + httpx.NewMockResponse(200, nil, []byte(`0: Accepted for delivery`)), + }, + }, + ExpectedMsgStatus: "W", + ExpectedRequests: []ExpectedRequest{{ + Params: url.Values{ + "text": {"☺"}, + "to": {"+250788383383"}, + "from": {"2020"}, + "coding": {"2"}, + "charset": {"utf8"}, + "dlr-mask": {"27"}, + "dlr-url": {"https://localhost/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%d"}, + "username": {"Username"}, + "password": {"Password"}, + }, + }}, }, { - 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: "Smart Encoding", + MsgText: "Fancy “Smart” Quotes", + MsgURN: "tel:+250788383383", + MsgHighPriority: false, + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/send*": { + httpx.NewMockResponse(200, nil, []byte(`0: Accepted for delivery`)), + }, + }, + ExpectedMsgStatus: "W", + ExpectedRequests: []ExpectedRequest{{ + Params: url.Values{ + "text": {`Fancy "Smart" Quotes`}, + "to": {"+250788383383"}, + "from": {"2020"}, + "dlr-mask": {"27"}, + "dlr-url": {"https://localhost/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%d"}, + "username": {"Username"}, + "password": {"Password"}, + }, + }}, + }, { - 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: "Not Routable", + MsgText: "Not Routable", + MsgURN: "tel:+250788383383", + MsgHighPriority: false, + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/send*": { + httpx.NewMockResponse(403, nil, []byte(`Not routable. Do not try again.`)), + }, + }, + ExpectedMsgStatus: "F", + ExpectedRequests: []ExpectedRequest{{ + Params: url.Values{ + "text": {"Not Routable"}, + "to": {"+250788383383"}, + "from": {"2020"}, + "dlr-mask": {"27"}, + "dlr-url": {"https://localhost/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%d"}, + "username": {"Username"}, + "password": {"Password"}, + }, + }}, }, { - 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: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MsgHighPriority: false, + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/send*": { + httpx.NewMockResponse(401, nil, []byte(`1: Unknown channel`)), + }, + }, + ExpectedMsgStatus: "E", + ExpectedRequests: []ExpectedRequest{{ + Params: url.Values{ + "text": {"Error Message"}, + "to": {"+250788383383"}, + "from": {"2020"}, + "dlr-mask": {"27"}, + "dlr-url": {"https://localhost/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%d"}, + "username": {"Username"}, + "password": {"Password"}, + }, + }}, }, + { - 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"}, + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/send*": { + httpx.NewMockResponse(200, nil, []byte(`0: Accepted for delivery`)), + }, + }, + ExpectedMsgStatus: "W", + ExpectedRequests: []ExpectedRequest{{ + Params: url.Values{ + "text": {"My pic!\nhttps://foo.bar/image.jpg"}, + "to": {"+250788383383"}, + "from": {"2020"}, + "priority": {"1"}, + "dlr-mask": {"27"}, + "dlr-url": {"https://localhost/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%d"}, + "username": {"Username"}, + "password": {"Password"}, + }, + }}, }, +} + +var customParamsTestCases = []OutgoingTestCase{ { - 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: "Custom Params", + MsgText: "Custom Params", + MsgURN: "tel:+250788383383", + MsgHighPriority: true, + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/send*": { + httpx.NewMockResponse(201, nil, []byte(`0: Accepted for delivery`)), + }, + }, + ExpectedMsgStatus: "W", + ExpectedRequests: []ExpectedRequest{{ + Params: url.Values{ + "text": {"Custom Params"}, + "to": {"+250788383383"}, + "from": {"2020"}, + "priority": {"1"}, + "dlr-mask": {"27"}, + "dlr-url": {"https://localhost/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%d"}, + "username": {"Username"}, + "password": {"Password"}, + "auth": {"foo"}, + }, + }}, }, } var nationalSendTestCases = []OutgoingTestCase{ { - 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, + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/send*": { + httpx.NewMockResponse(200, nil, []byte(`0: Accepted for delivery`)), + }, + }, + ExpectedMsgStatus: "W", + ExpectedRequests: []ExpectedRequest{{ + Params: url.Values{ + "text": {"success"}, + "to": {"788383383"}, + "from": {"2020"}, + "priority": {"1"}, + "dlr-mask": {"3"}, + "dlr-url": {"https://localhost/c/kn/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%d"}, + "username": {"Username"}, + "password": {"Password"}, + }, + }}, }, } func TestOutgoing(t *testing.T) { var defaultChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "KN", "2020", "US", map[string]any{ - "password": "Password", - "username": "Username"}) + "password": "Password", + "username": "Username", + courier.ConfigSendURL: "http://example.com/send", + }) + + var customParamsChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "KN", "2020", "US", + map[string]any{ + "password": "Password", + "username": "Username", + courier.ConfigSendURL: "http://example.com/send?auth=foo", + }) var nationalChannel = test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "KN", "2020", "US", map[string]any{ - "password": "Password", - "username": "Username", - "use_national": true, - "verify_ssl": false, - "dlr_mask": "3", + "password": "Password", + "username": "Username", + "use_national": true, + "verify_ssl": false, + "dlr_mask": "3", + courier.ConfigSendURL: "http://example.com/send", }) RunOutgoingTestCases(t, defaultChannel, newHandler(), defaultSendTestCases, []string{"Password"}, nil) + RunOutgoingTestCases(t, customParamsChannel, newHandler(), customParamsTestCases, []string{"Password"}, nil) RunOutgoingTestCases(t, nationalChannel, newHandler(), nationalSendTestCases, []string{"Password"}, nil) } From 725a77a53272a7eb39fcc5415582ecb76b185fff Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 21 Feb 2024 18:43:36 +0200 Subject: [PATCH 07/15] Rework KN handler to new send --- handlers/kannel/handler.go | 33 ++++++++------------------------- handlers/kannel/handler_test.go | 10 ++-------- 2 files changed, 10 insertions(+), 33 deletions(-) diff --git a/handlers/kannel/handler.go b/handlers/kannel/handler.go index d46fa474c..b71874791 100644 --- a/handlers/kannel/handler.go +++ b/handlers/kannel/handler.go @@ -118,26 +118,13 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.SendResult, clog *courier.ChannelLog) error { - // TODO convert functionality from legacy method below - return nil -} -func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *courier.ChannelLog) (courier.StatusUpdate, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") - if username == "" { - return nil, fmt.Errorf("no username set for KN channel") - } - password := msg.Channel().StringConfigForKey(courier.ConfigPassword, "") - if password == "" { - return nil, fmt.Errorf("no password set for KN channel") - } - sendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, "") - if sendURL == "" { - return nil, fmt.Errorf("no send url set for KN channel") + if username == "" || password == "" || sendURL == "" { + return courier.ErrChannelConfig } - dlrMask := msg.Channel().StringConfigForKey(configDLRMask, defaultDLRMask) callbackDomain := msg.Channel().CallbackDomain(h.Server().Config().Domain) @@ -200,7 +187,7 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour req, err := http.NewRequest(http.MethodGet, sendURL, nil) if err != nil { - return nil, err + return err } var resp *http.Response @@ -210,15 +197,11 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour resp, _, err = h.RequestHTTPInsecure(req, clog) } - status := h.Backend().NewStatusUpdate(msg.Channel(), msg.ID(), courier.MsgStatusErrored, clog) - if err == nil && resp.StatusCode/100 == 2 { - status.SetStatus(courier.MsgStatusWired) + if err != nil || resp.StatusCode/100 == 5 { + return courier.ErrConnectionFailed + } else if resp.StatusCode/100 != 2 { + return courier.ErrResponseStatus } - // kannel will respond with a 403 for non-routable numbers, fail permanently in these cases - if resp != nil && resp.StatusCode == 403 { - status.SetStatus(courier.MsgStatusFailed) - } - - return status, nil + return nil } diff --git a/handlers/kannel/handler_test.go b/handlers/kannel/handler_test.go index 7eac5dc37..b68383464 100644 --- a/handlers/kannel/handler_test.go +++ b/handlers/kannel/handler_test.go @@ -140,7 +140,6 @@ var defaultSendTestCases = []OutgoingTestCase{ httpx.NewMockResponse(200, nil, []byte(`0: Accepted for delivery`)), }, }, - ExpectedMsgStatus: "W", ExpectedRequests: []ExpectedRequest{{ Params: url.Values{ "text": {"Simple Message"}, @@ -163,7 +162,6 @@ var defaultSendTestCases = []OutgoingTestCase{ httpx.NewMockResponse(200, nil, []byte(`0: Accepted for delivery`)), }, }, - ExpectedMsgStatus: "W", ExpectedRequests: []ExpectedRequest{{ Params: url.Values{ "text": {"☺"}, @@ -188,7 +186,6 @@ var defaultSendTestCases = []OutgoingTestCase{ httpx.NewMockResponse(200, nil, []byte(`0: Accepted for delivery`)), }, }, - ExpectedMsgStatus: "W", ExpectedRequests: []ExpectedRequest{{ Params: url.Values{ "text": {`Fancy "Smart" Quotes`}, @@ -211,7 +208,6 @@ var defaultSendTestCases = []OutgoingTestCase{ httpx.NewMockResponse(403, nil, []byte(`Not routable. Do not try again.`)), }, }, - ExpectedMsgStatus: "F", ExpectedRequests: []ExpectedRequest{{ Params: url.Values{ "text": {"Not Routable"}, @@ -223,6 +219,7 @@ var defaultSendTestCases = []OutgoingTestCase{ "password": {"Password"}, }, }}, + ExpectedError: courier.ErrResponseStatus, }, { Label: "Error Sending", @@ -234,7 +231,6 @@ var defaultSendTestCases = []OutgoingTestCase{ httpx.NewMockResponse(401, nil, []byte(`1: Unknown channel`)), }, }, - ExpectedMsgStatus: "E", ExpectedRequests: []ExpectedRequest{{ Params: url.Values{ "text": {"Error Message"}, @@ -246,6 +242,7 @@ var defaultSendTestCases = []OutgoingTestCase{ "password": {"Password"}, }, }}, + ExpectedError: courier.ErrResponseStatus, }, { @@ -259,7 +256,6 @@ var defaultSendTestCases = []OutgoingTestCase{ httpx.NewMockResponse(200, nil, []byte(`0: Accepted for delivery`)), }, }, - ExpectedMsgStatus: "W", ExpectedRequests: []ExpectedRequest{{ Params: url.Values{ "text": {"My pic!\nhttps://foo.bar/image.jpg"}, @@ -286,7 +282,6 @@ var customParamsTestCases = []OutgoingTestCase{ httpx.NewMockResponse(201, nil, []byte(`0: Accepted for delivery`)), }, }, - ExpectedMsgStatus: "W", ExpectedRequests: []ExpectedRequest{{ Params: url.Values{ "text": {"Custom Params"}, @@ -314,7 +309,6 @@ var nationalSendTestCases = []OutgoingTestCase{ httpx.NewMockResponse(200, nil, []byte(`0: Accepted for delivery`)), }, }, - ExpectedMsgStatus: "W", ExpectedRequests: []ExpectedRequest{{ Params: url.Values{ "text": {"success"}, From 1bd2574a771bb37a1f4ae6a4d683bc97b3e6dbe5 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 21 Feb 2024 18:52:18 +0200 Subject: [PATCH 08/15] Rework KWA handler to new send --- handlers/kaleyra/handler.go | 25 ++++++++++--------------- handlers/kaleyra/handler_test.go | 17 +++++++---------- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/handlers/kaleyra/handler.go b/handlers/kaleyra/handler.go index 9bf828a52..0c1922957 100644 --- a/handlers/kaleyra/handler.go +++ b/handlers/kaleyra/handler.go @@ -135,20 +135,13 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.SendResult, clog *courier.ChannelLog) error { - // TODO convert functionality from legacy method below - return nil -} - -func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *courier.ChannelLog) (courier.StatusUpdate, error) { accountSID := msg.Channel().StringConfigForKey(configAccountSID, "") apiKey := msg.Channel().StringConfigForKey(configApiKey, "") if accountSID == "" || apiKey == "" { - return nil, errors.New("no account_sid or api_key config") + return courier.ErrChannelConfig } - status := h.Backend().NewStatusUpdate(msg.Channel(), msg.ID(), courier.MsgStatusErrored, clog) - sendURL := fmt.Sprintf("%s/v1/%s/messages", baseURL, accountSID) var kwaResp *http.Response var kwaRespBody []byte @@ -226,19 +219,21 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour kwaResp, kwaRespBody, kwaErr = h.RequestHTTP(req, clog) } - if kwaErr != nil || kwaResp.StatusCode/100 != 2 { - status.SetStatus(courier.MsgStatusFailed) - return status, nil + if kwaErr != nil || kwaResp.StatusCode/100 == 5 { + return courier.ErrConnectionFailed + } else if kwaResp.StatusCode/100 != 2 { + return courier.ErrResponseStatus } // record external id from the last sent msg request externalID, err := jsonparser.GetString(kwaRespBody, "id") - if err == nil { - status.SetExternalID(externalID) + if err != nil { + clog.Error(courier.ErrorResponseValueMissing("id")) + } else { + res.AddExternalID(externalID) } - status.SetStatus(courier.MsgStatusWired) - return status, nil + return nil } func (h *handler) newSendForm(channel courier.Channel, msgType, toContact string) map[string]string { diff --git a/handlers/kaleyra/handler_test.go b/handlers/kaleyra/handler_test.go index b689e75f2..69f059d6c 100644 --- a/handlers/kaleyra/handler_test.go +++ b/handlers/kaleyra/handler_test.go @@ -101,10 +101,9 @@ func TestIncoming(t *testing.T) { var sendTestCases = []OutgoingTestCase{ { - Label: "Plain Send", - MsgText: "Simple Message", - MsgURN: "whatsapp:14133881111", - ExpectedMsgStatus: "W", + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "whatsapp:14133881111", MockResponses: map[string][]*httpx.MockResponse{ "https://api.kaleyra.io/v1/SID/messages": {httpx.NewMockResponse(200, nil, []byte(`{"id":"58f86fab-85c5-4f7c-9b68-9c323248afc4:0"}`))}, }, @@ -129,8 +128,7 @@ var sendTestCases = []OutgoingTestCase{ Body: "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", }, }, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"58f86fab-85c5-4f7c-9b68-9c323248afc4:0"}, + ExpectedExtIDs: []string{"58f86fab-85c5-4f7c-9b68-9c323248afc4:0"}, }, { Label: "Plain Send Error", @@ -145,7 +143,7 @@ var sendTestCases = []OutgoingTestCase{ Body: "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", }, }, - ExpectedMsgStatus: "F", + ExpectedError: courier.ErrResponseStatus, }, { Label: "Medias Send", @@ -170,8 +168,7 @@ var sendTestCases = []OutgoingTestCase{ {}, {BodyContains: "video bytes"}, }, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"f75fbe1e-a0c0-4923-96e8-5043aa617b2b:0"}, + ExpectedExtIDs: []string{"f75fbe1e-a0c0-4923-96e8-5043aa617b2b:0"}, }, { Label: "Media Send Error", @@ -196,7 +193,7 @@ var sendTestCases = []OutgoingTestCase{ {}, {BodyContains: "video bytes"}, }, - ExpectedMsgStatus: "F", + ExpectedError: courier.ErrResponseStatus, }, } From ec01b2423363b463e9aa993339e9259ad66d650c Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 21 Feb 2024 18:59:23 +0200 Subject: [PATCH 09/15] Rework JCL handler to new send --- handlers/justcall/handler.go | 38 +++++++++++-------------------- handlers/justcall/handler_test.go | 9 +++----- 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/handlers/justcall/handler.go b/handlers/justcall/handler.go index 32e8057b4..4af991851 100644 --- a/handlers/justcall/handler.go +++ b/handlers/justcall/handler.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "net/http" + "strconv" "strings" "time" @@ -153,22 +154,12 @@ type mtPayload struct { } func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.SendResult, clog *courier.ChannelLog) error { - // TODO convert functionality from legacy method below - return nil -} - -func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *courier.ChannelLog) (courier.StatusUpdate, 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") + if apiKey == "" || apiSecret == "" { + return courier.ErrChannelConfig } - status := h.Backend().NewStatusUpdate(msg.Channel(), msg.ID(), courier.MsgStatusErrored, clog) mediaURLs := make([]string, 0, 5) text := msg.Text() @@ -188,38 +179,35 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour req, err := http.NewRequest(http.MethodPost, sendURL, bytes.NewReader(jsonx.MustMarshal(payload))) if err != nil { - return nil, err + return 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 := h.RequestHTTP(req, clog) - if err != nil || resp.StatusCode/100 != 2 { - return status, nil + if err != nil || resp.StatusCode/100 == 5 { + return courier.ErrConnectionFailed + } else if resp.StatusCode/100 != 2 { + return courier.ErrResponseStatus } respStatus, err := jsonparser.GetString(respBody, "status") if err != nil { clog.Error(courier.ErrorResponseValueMissing("status")) - return status, h.Backend().WriteChannelLog(ctx, clog) } if respStatus != "success" { - return status, nil + return courier.ErrFailedWithReason("", "got non-success status") } externalID, err := jsonparser.GetInt(respBody, "id") if err != nil { clog.Error(courier.ErrorResponseValueMissing("id")) - return status, h.Backend().WriteChannelLog(ctx, clog) - } - - if externalID != 0 { - status.SetExternalID(fmt.Sprintf("%d", externalID)) + } else { + res.AddExternalID(strconv.Itoa(int(externalID))) } - status.SetStatus(courier.MsgStatusWired) - return status, nil - + return nil } diff --git a/handlers/justcall/handler_test.go b/handlers/justcall/handler_test.go index deb547abe..644aed82a 100644 --- a/handlers/justcall/handler_test.go +++ b/handlers/justcall/handler_test.go @@ -285,8 +285,7 @@ var defaultSendTestCases = []OutgoingTestCase{ }, Body: `{"from":"2020","to":"+250788383383","body":"Simple Message"}`, }}, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"12345"}, + ExpectedExtIDs: []string{"12345"}, }, { Label: "Send Document", @@ -306,8 +305,7 @@ var defaultSendTestCases = []OutgoingTestCase{ }, Body: `{"from":"2020","to":"+250788383383","body":"This is some text.","media_url":"https://foo.bar/document.pdf"}`, }}, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"12345"}, + ExpectedExtIDs: []string{"12345"}, }, { Label: "ID Error", @@ -326,7 +324,6 @@ var defaultSendTestCases = []OutgoingTestCase{ }, Body: `{"from":"2020","to":"+250788383383","body":"ID Error"}`, }}, - ExpectedMsgStatus: "E", ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("id")}, }, { @@ -346,7 +343,7 @@ var defaultSendTestCases = []OutgoingTestCase{ }, Body: `{"from":"2020","to":"+250788383383","body":"Error"}`, }}, - ExpectedMsgStatus: "E", + ExpectedError: courier.ErrResponseStatus, }, } From e4229972e0c8a198a8e78a0f4475574405750f84 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 21 Feb 2024 19:02:15 +0200 Subject: [PATCH 10/15] Rework JC handler to new send --- handlers/jiochat/handler.go | 17 ++++++----------- handlers/jiochat/handler_test.go | 5 +---- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/handlers/jiochat/handler.go b/handlers/jiochat/handler.go index 3fd527019..963a50086 100644 --- a/handlers/jiochat/handler.go +++ b/handlers/jiochat/handler.go @@ -163,17 +163,11 @@ type mtPayload struct { } func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.SendResult, clog *courier.ChannelLog) error { - // TODO convert functionality from legacy method below - return nil -} - -func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *courier.ChannelLog) (courier.StatusUpdate, error) { accessToken, err := h.getAccessToken(ctx, msg.Channel(), clog) if err != nil { - return nil, err + return courier.ErrChannelConfig } - status := h.Backend().NewStatusUpdate(msg.Channel(), msg.ID(), courier.MsgStatusErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) for _, part := range parts { jcMsg := &mtPayload{} @@ -191,14 +185,15 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken)) resp, _, err := h.RequestHTTP(req, clog) - if err != nil || resp.StatusCode/100 != 2 { - return status, nil + if err != nil || resp.StatusCode/100 == 5 { + return courier.ErrConnectionFailed + } else if resp.StatusCode/100 != 2 { + return courier.ErrResponseStatus } - status.SetStatus(courier.MsgStatusWired) } - return status, nil + return nil } // DescribeURN handles Jiochat contact details diff --git a/handlers/jiochat/handler_test.go b/handlers/jiochat/handler_test.go index cd5825f94..13bc14ed3 100644 --- a/handlers/jiochat/handler_test.go +++ b/handlers/jiochat/handler_test.go @@ -362,7 +362,6 @@ var defaultSendTestCases = []OutgoingTestCase{ }, Body: `{"msgtype":"text","touser":"12345","text":{"content":"Simple Message ☺"}}`, }}, - ExpectedMsgStatus: "W", }, { Label: "Long Send", @@ -392,7 +391,6 @@ var defaultSendTestCases = []OutgoingTestCase{ Body: `{"msgtype":"text","touser":"12345","text":{"content":"I need to keep adding more things to make it work"}}`, }, }, - ExpectedMsgStatus: "W", }, { Label: "Send Attachment", @@ -412,7 +410,6 @@ var defaultSendTestCases = []OutgoingTestCase{ }, Body: `{"msgtype":"text","touser":"12345","text":{"content":"My pic!\nhttps://foo.bar/image.jpg"}}`, }}, - ExpectedMsgStatus: "W", }, { Label: "Error Sending", @@ -423,7 +420,7 @@ var defaultSendTestCases = []OutgoingTestCase{ httpx.NewMockResponse(401, nil, []byte(``)), }, }, - ExpectedMsgStatus: "E", + ExpectedError: courier.ErrResponseStatus, }, } From c8c15c0f6b3d3dec16fcfdae484a9cb85782ba01 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 21 Feb 2024 19:06:37 +0200 Subject: [PATCH 11/15] Rework JS handler to new send --- handlers/jasmin/handler.go | 33 +++++++++------------------------ handlers/jasmin/handler_test.go | 14 +++++--------- 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/handlers/jasmin/handler.go b/handlers/jasmin/handler.go index c224fc1e3..d214d409f 100644 --- a/handlers/jasmin/handler.go +++ b/handlers/jasmin/handler.go @@ -119,24 +119,11 @@ func writeJasminACK(w http.ResponseWriter) error { } func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.SendResult, clog *courier.ChannelLog) error { - // TODO convert functionality from legacy method below - return nil -} - -func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *courier.ChannelLog) (courier.StatusUpdate, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") - if username == "" { - return nil, fmt.Errorf("no username set for JS channel") - } - password := msg.Channel().StringConfigForKey(courier.ConfigPassword, "") - if password == "" { - return nil, fmt.Errorf("no password set for JS channel") - } - sendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, "") - if sendURL == "" { - return nil, fmt.Errorf("no send url set for JS channel") + if username == "" || password == "" || sendURL == "" { + return courier.ErrChannelConfig } callbackDomain := msg.Channel().CallbackDomain(h.Server().Config().Domain) @@ -161,23 +148,21 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour req, err := http.NewRequest(http.MethodGet, fullURL.String(), nil) if err != nil { - return nil, err + return err } - status := h.Backend().NewStatusUpdate(msg.Channel(), msg.ID(), courier.MsgStatusErrored, clog) - resp, respBody, err := h.RequestHTTP(req, clog) - if err != nil || resp.StatusCode/100 != 2 { - return status, nil + if err != nil || resp.StatusCode/100 == 5 { + return courier.ErrConnectionFailed + } else if resp.StatusCode/100 != 2 { + return courier.ErrResponseStatus } - status.SetStatus(courier.MsgStatusWired) - // try to read our external id out matches := idRegex.FindSubmatch(respBody) if len(matches) == 2 { - status.SetExternalID(string(matches[1])) + res.AddExternalID(string(matches[1])) } - return status, nil + return nil } diff --git a/handlers/jasmin/handler_test.go b/handlers/jasmin/handler_test.go index dff7da8e9..50dc84572 100644 --- a/handlers/jasmin/handler_test.go +++ b/handlers/jasmin/handler_test.go @@ -109,8 +109,7 @@ var defaultSendTestCases = []OutgoingTestCase{ "dlr-url": {"https://localhost/c/js/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status"}, }, }}, - ExpectedExtIDs: []string{"External ID1"}, - ExpectedMsgStatus: "W", + ExpectedExtIDs: []string{"External ID1"}, }, { Label: "Unicode Send", @@ -135,8 +134,7 @@ var defaultSendTestCases = []OutgoingTestCase{ "dlr-url": {"https://localhost/c/js/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status"}, }, }}, - ExpectedExtIDs: []string{"External ID1"}, - ExpectedMsgStatus: "W", + ExpectedExtIDs: []string{"External ID1"}, }, { Label: "Smart Encoding", @@ -161,8 +159,7 @@ var defaultSendTestCases = []OutgoingTestCase{ "dlr-url": {"https://localhost/c/js/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status"}, }, }}, - ExpectedExtIDs: []string{"External ID1"}, - ExpectedMsgStatus: "W", + ExpectedExtIDs: []string{"External ID1"}, }, { Label: "Send Attachment", @@ -189,8 +186,7 @@ var defaultSendTestCases = []OutgoingTestCase{ "dlr-url": {"https://localhost/c/js/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status"}, }, }}, - ExpectedExtIDs: []string{"External ID1"}, - ExpectedMsgStatus: "W", + ExpectedExtIDs: []string{"External ID1"}, }, { Label: "Error Sending", @@ -216,7 +212,7 @@ var defaultSendTestCases = []OutgoingTestCase{ "dlr-url": {"https://localhost/c/js/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status"}, }, }}, - ExpectedMsgStatus: "E", + ExpectedError: courier.ErrResponseStatus, }, } From a157f5a84ffc6c1299945742dd7c123f040ed267 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 21 Feb 2024 19:14:25 +0200 Subject: [PATCH 12/15] Rework IB handler to new send --- handlers/infobip/handler.go | 39 +++++++++++++------------------- handlers/infobip/handler_test.go | 14 +++++------- 2 files changed, 22 insertions(+), 31 deletions(-) diff --git a/handlers/infobip/handler.go b/handlers/infobip/handler.go index fe0a02931..8bd3c3331 100644 --- a/handlers/infobip/handler.go +++ b/handlers/infobip/handler.go @@ -159,19 +159,10 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w } func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.SendResult, clog *courier.ChannelLog) error { - // TODO convert functionality from legacy method below - return nil -} - -func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *courier.ChannelLog) (courier.StatusUpdate, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") - if username == "" { - return nil, fmt.Errorf("no username set for IB channel") - } - password := msg.Channel().StringConfigForKey(courier.ConfigPassword, "") - if password == "" { - return nil, fmt.Errorf("no password set for IB channel") + if username == "" || password == "" { + return courier.ErrChannelConfig } transliteration := msg.Channel().StringConfigForKey(configTransliteration, "") @@ -201,38 +192,40 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour requestBody := &bytes.Buffer{} err := json.NewEncoder(requestBody).Encode(ibMsg) if err != nil { - return nil, err + return err } // build our request req, err := http.NewRequest(http.MethodPost, sendURL, requestBody) if err != nil { - return nil, err + return err } req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") req.SetBasicAuth(username, password) - status := h.Backend().NewStatusUpdate(msg.Channel(), msg.ID(), courier.MsgStatusErrored, clog) - resp, respBody, err := h.RequestHTTP(req, clog) - if err != nil || resp.StatusCode/100 != 2 { - return status, nil + if err != nil || resp.StatusCode/100 == 5 { + return courier.ErrConnectionFailed + } else if resp.StatusCode/100 != 2 { + return courier.ErrResponseStatus } groupID, err := jsonparser.GetInt(respBody, "messages", "[0]", "status", "groupId") if err != nil || (groupID != 1 && groupID != 3) { clog.Error(courier.ErrorResponseValueUnexpected("groupId", "1", "3")) - return status, nil + return courier.ErrFailedWithReason("", "unexpected groupId value") } - externalID, _ := jsonparser.GetString(respBody, "messages", "[0]", "messageId") - if externalID != "" { - status.SetExternalID(externalID) + externalID, err := jsonparser.GetString(respBody, "messages", "[0]", "messageId") + if err != nil { + clog.Error(courier.ErrorResponseValueMissing("messageId")) + } else { + + res.AddExternalID(externalID) } - status.SetStatus(courier.MsgStatusWired) - return status, nil + return nil } func (h *handler) RedactValues(ch courier.Channel) []string { diff --git a/handlers/infobip/handler_test.go b/handlers/infobip/handler_test.go index 4e93c9dc2..29d810f0f 100644 --- a/handlers/infobip/handler_test.go +++ b/handlers/infobip/handler_test.go @@ -316,8 +316,7 @@ var defaultSendTestCases = []OutgoingTestCase{ }, Body: `{"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", - ExpectedExtIDs: []string{"12345"}, + ExpectedExtIDs: []string{"12345"}, }, { Label: "Unicode Send", @@ -338,7 +337,7 @@ var defaultSendTestCases = []OutgoingTestCase{ }, Body: `{"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"}]}`, }}, - ExpectedMsgStatus: "W", + ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("messageId")}, }, { Label: "Send Attachment", @@ -360,7 +359,7 @@ var defaultSendTestCases = []OutgoingTestCase{ }, Body: `{"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"}]}`, }}, - ExpectedMsgStatus: "W", + ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("messageId")}, }, { Label: "Error Sending", @@ -379,7 +378,7 @@ var defaultSendTestCases = []OutgoingTestCase{ }, Body: `{"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"}]}`, }}, - ExpectedMsgStatus: "E", + ExpectedError: courier.ErrResponseStatus, }, { Label: "Error groupId", @@ -400,7 +399,7 @@ var defaultSendTestCases = []OutgoingTestCase{ }, Body: `{"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", + ExpectedError: courier.ErrFailedWithReason("", "unexpected groupId value"), ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseValueUnexpected("groupId", "1", "3")}, }, } @@ -425,8 +424,7 @@ var transSendTestCases = []OutgoingTestCase{ }, Body: `{"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"}]}`, }}, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"12345"}, + ExpectedExtIDs: []string{"12345"}, }, } From 1d61db7c8e0219addda9ad7f56bf48e3da1766f3 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 21 Feb 2024 19:20:45 +0200 Subject: [PATCH 13/15] Rework I2 handler to new send --- handlers/i2sms/handler.go | 39 +++++++++++----------------------- handlers/i2sms/handler_test.go | 11 ++++------ 2 files changed, 16 insertions(+), 34 deletions(-) diff --git a/handlers/i2sms/handler.go b/handlers/i2sms/handler.go index 51fa6ba11..8174ded64 100644 --- a/handlers/i2sms/handler.go +++ b/handlers/i2sms/handler.go @@ -81,30 +81,17 @@ type mtResponse struct { SessionID string `json:"session_id"` } `json:"result"` ErrorCode string `json:"error_code"` + ErrorDesc string `json:"error_desc"` } func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.SendResult, clog *courier.ChannelLog) error { - // TODO convert functionality from legacy method below - return nil -} - -func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *courier.ChannelLog) (courier.StatusUpdate, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") - if username == "" { - return nil, fmt.Errorf("no username set for I2 channel") - } - password := msg.Channel().StringConfigForKey(courier.ConfigPassword, "") - if password == "" { - return nil, fmt.Errorf("no password set for I2 channel") - } - channelHash := msg.Channel().StringConfigForKey(configChannelHash, "") - if channelHash == "" { - return nil, fmt.Errorf("no channel_hash set for I2 channel") + if username == "" || password == "" || channelHash == "" { + return courier.ErrChannelConfig } - status := h.Backend().NewStatusUpdate(msg.Channel(), msg.ID(), courier.MsgStatusErrored, clog) for _, part := range handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength) { form := url.Values{ "action": []string{"send_single"}, @@ -115,37 +102,35 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour req, err := http.NewRequest(http.MethodPost, sendURL, strings.NewReader(form.Encode())) if err != nil { - return nil, err + return err } req.SetBasicAuth(username, password) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") resp, respBody, err := h.RequestHTTP(req, clog) - if err != nil || resp.StatusCode/100 != 2 { - return status, nil + if err != nil || resp.StatusCode/100 == 5 { + return courier.ErrConnectionFailed + } else if resp.StatusCode/100 != 2 { + return courier.ErrResponseStatus } // parse our response as JSON response := &mtResponse{} err = json.Unmarshal(respBody, response) if err != nil { - clog.Error(courier.ErrorResponseUnparseable("JSON")) - break + return courier.ErrResponseUnparseable } // we always get 00 on success if response.ErrorCode == "00" { - status.SetStatus(courier.MsgStatusWired) - status.SetExternalID(response.Result.SessionID) + res.AddExternalID(response.Result.SessionID) } else { - status.SetStatus(courier.MsgStatusFailed) - clog.Error(courier.ErrorResponseValueUnexpected("error_code", "00")) - break + return courier.ErrFailedWithReason(response.ErrorCode, response.ErrorDesc) } } - return status, nil + return nil } func (h *handler) RedactValues(ch courier.Channel) []string { diff --git a/handlers/i2sms/handler_test.go b/handlers/i2sms/handler_test.go index 949bffecc..f83e22eca 100644 --- a/handlers/i2sms/handler_test.go +++ b/handlers/i2sms/handler_test.go @@ -66,8 +66,7 @@ var defaultSendTestCases = []OutgoingTestCase{ }, }, }, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"5b8fc97d58795484819426"}, + ExpectedExtIDs: []string{"5b8fc97d58795484819426"}, }, { Label: "Invalid JSON", @@ -88,8 +87,7 @@ var defaultSendTestCases = []OutgoingTestCase{ }, }, }, - ExpectedMsgStatus: "E", - ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseUnparseable("JSON")}, + ExpectedError: courier.ErrResponseUnparseable, }, { Label: "Error Response", @@ -110,8 +108,7 @@ var defaultSendTestCases = []OutgoingTestCase{ }, }, }, - ExpectedMsgStatus: "F", - ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseValueUnexpected("error_code", "00")}, + ExpectedError: courier.ErrFailedWithReason("10", "Failed"), }, { Label: "Error Sending", @@ -132,7 +129,7 @@ var defaultSendTestCases = []OutgoingTestCase{ }, }, }, - ExpectedMsgStatus: "E", + ExpectedError: courier.ErrConnectionFailed, }, } From 190581cf705fe964740c4ff597b9c28d3506adff Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Tue, 27 Feb 2024 16:32:33 +0200 Subject: [PATCH 14/15] Remove channel log for IB unexpected group --- handlers/infobip/handler.go | 1 - handlers/infobip/handler_test.go | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/handlers/infobip/handler.go b/handlers/infobip/handler.go index 8bd3c3331..ef8538953 100644 --- a/handlers/infobip/handler.go +++ b/handlers/infobip/handler.go @@ -213,7 +213,6 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.Sen groupID, err := jsonparser.GetInt(respBody, "messages", "[0]", "status", "groupId") if err != nil || (groupID != 1 && groupID != 3) { - clog.Error(courier.ErrorResponseValueUnexpected("groupId", "1", "3")) return courier.ErrFailedWithReason("", "unexpected groupId value") } diff --git a/handlers/infobip/handler_test.go b/handlers/infobip/handler_test.go index 29d810f0f..1250e68d3 100644 --- a/handlers/infobip/handler_test.go +++ b/handlers/infobip/handler_test.go @@ -399,8 +399,7 @@ var defaultSendTestCases = []OutgoingTestCase{ }, Body: `{"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"}]}`, }}, - ExpectedError: courier.ErrFailedWithReason("", "unexpected groupId value"), - ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseValueUnexpected("groupId", "1", "3")}, + ExpectedError: courier.ErrFailedWithReason("", "unexpected groupId value"), }, } From 08ce2dcee9adf4bff568245d86bec0aed0bb9f20 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 28 Feb 2024 15:46:07 +0200 Subject: [PATCH 15/15] Adjust send errors --- handlers/infobip/handler.go | 2 +- handlers/infobip/handler_test.go | 2 +- handlers/justcall/handler.go | 2 +- handlers/justcall/handler_test.go | 38 +++++++++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/handlers/infobip/handler.go b/handlers/infobip/handler.go index ef8538953..4eb419435 100644 --- a/handlers/infobip/handler.go +++ b/handlers/infobip/handler.go @@ -213,7 +213,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.Sen groupID, err := jsonparser.GetInt(respBody, "messages", "[0]", "status", "groupId") if err != nil || (groupID != 1 && groupID != 3) { - return courier.ErrFailedWithReason("", "unexpected groupId value") + return courier.ErrResponseUnexpected } externalID, err := jsonparser.GetString(respBody, "messages", "[0]", "messageId") diff --git a/handlers/infobip/handler_test.go b/handlers/infobip/handler_test.go index 1250e68d3..17cefaf99 100644 --- a/handlers/infobip/handler_test.go +++ b/handlers/infobip/handler_test.go @@ -399,7 +399,7 @@ var defaultSendTestCases = []OutgoingTestCase{ }, Body: `{"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"}]}`, }}, - ExpectedError: courier.ErrFailedWithReason("", "unexpected groupId value"), + ExpectedError: courier.ErrResponseUnexpected, }, } diff --git a/handlers/justcall/handler.go b/handlers/justcall/handler.go index 4af991851..0941ad7e8 100644 --- a/handlers/justcall/handler.go +++ b/handlers/justcall/handler.go @@ -198,7 +198,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.Sen clog.Error(courier.ErrorResponseValueMissing("status")) } if respStatus != "success" { - return courier.ErrFailedWithReason("", "got non-success status") + return courier.ErrResponseUnexpected } diff --git a/handlers/justcall/handler_test.go b/handlers/justcall/handler_test.go index 644aed82a..da45385cf 100644 --- a/handlers/justcall/handler_test.go +++ b/handlers/justcall/handler_test.go @@ -326,6 +326,25 @@ var defaultSendTestCases = []OutgoingTestCase{ }}, ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("id")}, }, + { + Label: "Error Sending", + MsgText: "Error", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "https://api.justcall.io/v1/texts/new": { + httpx.NewMockResponse(200, nil, []byte(`{ "status": "fail" }`)), + }, + }, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "api_key:api_secret", + }, + Body: `{"from":"2020","to":"+250788383383","body":"Error"}`, + }}, + ExpectedError: courier.ErrResponseUnexpected, + }, { Label: "Error", MsgText: "Error", @@ -345,6 +364,25 @@ var defaultSendTestCases = []OutgoingTestCase{ }}, ExpectedError: courier.ErrResponseStatus, }, + { + Label: "Error Connection", + MsgText: "Error", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "https://api.justcall.io/v1/texts/new": { + httpx.NewMockResponse(500, nil, []byte(`Bad Gateway`)), + }, + }, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": "api_key:api_secret", + }, + Body: `{"from":"2020","to":"+250788383383","body":"Error"}`, + }}, + ExpectedError: courier.ErrConnectionFailed, + }, } func TestOutgoing(t *testing.T) {