blob: 0c0667496bf40576753d349d194261819c3c558c [file] [log] [blame]
package emailservice
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/sendgrid/sendgrid-go"
"github.com/sendgrid/sendgrid-go/helpers/mail"
"github.com/stretchr/testify/require"
"go.skia.org/infra/go/metrics2"
"go.skia.org/infra/go/testutils/unittest"
)
const myMesageID = "<abcdef>"
var errMyMockError = fmt.Errorf("my mock error")
const (
validMessage = `From: Alert Service <alerts@skia.org>
To: test@example.com
Subject: An Alert!
Content-Type: text/html; charset=UTF-8
References: some-reference-id
In-Reply-To: some-reference-id
<html>
<body>
<div itemscope itemtype="http://schema.org/EmailMessage">
<div itemprop="potentialAction" itemscope itemtype="http://schema.org/ViewAction">
<link itemprop="target" href="https://example.com"/>
<meta itemprop="name" content="Example"/>
</div>
<meta itemprop="description" content="Click the link"/>
</div>
<h1>Something happened</h1>
</body>
</html>
`
)
func createAppForTest(t *testing.T, handler http.Handler) *App {
ret := &App{
sendSuccess: metrics2.GetCounter("emailservice_send_success"),
sendFailure: metrics2.GetCounter("emailservice_send_failure"),
}
ret.sendFailure.Reset()
ret.sendSuccess.Reset()
if handler != nil {
s := httptest.NewServer(handler)
t.Cleanup(s.Close)
ret.sendgridClient = &sendgrid.Client{
Request: sendgrid.GetRequest("my key", "/v3/mail/send", s.URL),
}
}
return ret
}
func TestAppIncomingEmaiHandler_HappyPath(t *testing.T) {
unittest.SmallTest(t)
app := createAppForTest(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("X-Message-Id", myMesageID)
resp := Response{
// No errors in response means the request was a success.
}
err := json.NewEncoder(w).Encode(resp)
require.NoError(t, err)
}))
w := httptest.NewRecorder()
r := httptest.NewRequest("POST", "/send", bytes.NewBufferString(validMessage))
app.incomingEmaiHandler(w, r)
require.Equal(t, http.StatusOK, w.Code)
require.Equal(t, myMesageID, w.Header().Get("X-Message-Id"))
require.Equal(t, int64(0), app.sendFailure.Get())
require.Equal(t, int64(1), app.sendSuccess.Get())
}
func TestAppIncomingEmaiHandler_RequestBodyIsInvalidRFC2822Message_ReturnsHTTPError(t *testing.T) {
unittest.SmallTest(t)
app := createAppForTest(t, nil)
w := httptest.NewRecorder()
r := httptest.NewRequest("POST", "/send", bytes.NewBufferString(""))
app.incomingEmaiHandler(w, r)
require.Equal(t, http.StatusBadRequest, w.Code)
require.Equal(t, "Failed to convert RFC2822 body to SendGrid API format\n", w.Body.String())
require.Equal(t, int64(1), app.sendFailure.Get())
require.Equal(t, int64(0), app.sendSuccess.Get())
}
func TestAppIncomingEmaiHandler_ServerReturnsError_ReturnsHTTPError(t *testing.T) {
unittest.SmallTest(t)
app := createAppForTest(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resp := Response{
Errors: []Error{
{
Message: "something failed on the server",
},
},
}
err := json.NewEncoder(w).Encode(resp)
require.NoError(t, err)
w.WriteHeader(http.StatusInternalServerError)
}))
w := httptest.NewRecorder()
r := httptest.NewRequest("POST", "/send", bytes.NewBufferString(validMessage))
app.incomingEmaiHandler(w, r)
require.Equal(t, http.StatusBadRequest, w.Code)
require.Contains(t, w.Body.String(), "something failed on the server")
require.Equal(t, int64(1), app.sendFailure.Get())
require.Equal(t, int64(0), app.sendSuccess.Get())
}
func TestConvertRFC2822ToSendGrid_HappyPath(t *testing.T) {
unittest.SmallTest(t)
body := bytes.NewBufferString(`From: Alert Service <alerts@skia.org>
To: test@example.com, B <b@example.com>
Subject: An Alert!
Content-Type: text/html; charset=UTF-8
References: some-reference-id
In-Reply-To: some-reference-id
Hi!
`)
m, err := convertRFC2822ToSendGrid(body)
require.NoError(t, err)
require.Equal(t, "{\"from\":{\"name\":\"Alert Service\",\"email\":\"alerts@skia.org\"},\"subject\":\"An Alert!\",\"personalizations\":[{\"to\":[{\"email\":\"test@example.com\"},{\"name\":\"B\",\"email\":\"b@example.com\"}]}],\"content\":[{\"type\":\"text/html\",\"value\":\"Hi!\\n\"}]}", string(mail.GetRequestBody(m)))
}
func TestConvertRFC2822ToSendGrid_ToLineIsInvalid_ReturnsError(t *testing.T) {
unittest.SmallTest(t)
body := bytes.NewBufferString(`From: Alert Service <alerts@skia.org>
To: you
Subject: An Alert!
Content-Type: text/html; charset=UTF-8
Hi!
`)
_, err := convertRFC2822ToSendGrid(body)
require.Contains(t, err.Error(), "Failed to parse To: address")
}
func TestConvertRFC2822ToSendGrid_FromLineIsInvalid_ReturnsError(t *testing.T) {
unittest.SmallTest(t)
body := bytes.NewBufferString(`From: me
To: you@example.com
Subject: An Alert!
Hi!
`)
_, err := convertRFC2822ToSendGrid(body)
require.Contains(t, err.Error(), "Failed to parse From: address")
}