mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
[MM-47953] Outgoing webhook does not trigger when using multiple callback URLs (#22394)
Co-authored-by: Michael Kochell <6913320+mickmister@users.noreply.github.com>
This commit is contained in:
parent
5dbf874d1e
commit
f8fc02791b
@ -95,23 +95,30 @@ func (a *App) handleWebhookEvents(c request.CTX, post *model.Post, team *model.T
|
||||
}
|
||||
|
||||
func (a *App) TriggerWebhook(c request.CTX, payload *model.OutgoingWebhookPayload, hook *model.OutgoingWebhook, post *model.Post, channel *model.Channel) {
|
||||
var body io.Reader
|
||||
var contentType string
|
||||
var jsonBytes []byte
|
||||
var err error
|
||||
|
||||
contentType := "application/x-www-form-urlencoded"
|
||||
if hook.ContentType == "application/json" {
|
||||
js, err := json.Marshal(payload)
|
||||
contentType = "application/json"
|
||||
jsonBytes, err = json.Marshal(payload)
|
||||
if err != nil {
|
||||
c.Logger().Warn("Failed to encode to JSON", mlog.Err(err))
|
||||
return
|
||||
}
|
||||
body = bytes.NewReader(js)
|
||||
contentType = "application/json"
|
||||
} else {
|
||||
body = strings.NewReader(payload.ToFormValues())
|
||||
contentType = "application/x-www-form-urlencoded"
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for i := range hook.CallbackURLs {
|
||||
var body io.Reader
|
||||
if hook.ContentType == "application/json" {
|
||||
body = bytes.NewReader(jsonBytes)
|
||||
} else {
|
||||
body = strings.NewReader(payload.ToFormValues())
|
||||
}
|
||||
wg.Add(1)
|
||||
|
||||
// Get the callback URL by index to properly capture it for the go func
|
||||
url := hook.CallbackURLs[i]
|
||||
|
||||
|
@ -756,6 +756,101 @@ func TestTriggerOutGoingWebhookWithUsernameAndIconURL(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTriggerOutGoingWebhookWithMultipleURLs(t *testing.T) {
|
||||
getPayload := func(hook *model.OutgoingWebhook, th *TestHelper, channel *model.Channel) *model.OutgoingWebhookPayload {
|
||||
return &model.OutgoingWebhookPayload{
|
||||
Token: hook.Token,
|
||||
TeamId: hook.TeamId,
|
||||
TeamDomain: th.BasicTeam.Name,
|
||||
ChannelId: channel.Id,
|
||||
ChannelName: channel.Name,
|
||||
Timestamp: th.BasicPost.CreateAt,
|
||||
UserId: th.BasicPost.UserId,
|
||||
UserName: th.BasicUser.Username,
|
||||
PostId: th.BasicPost.Id,
|
||||
Text: th.BasicPost.Message,
|
||||
TriggerWord: "Abracadabra",
|
||||
FileIds: strings.Join(th.BasicPost.FileIds, ","),
|
||||
}
|
||||
}
|
||||
|
||||
createOutgoingWebhook := func(channel *model.Channel, testCallBackURLs []string, th *TestHelper) (*model.OutgoingWebhook, *model.AppError) {
|
||||
outgoingWebhook := model.OutgoingWebhook{
|
||||
ChannelId: channel.Id,
|
||||
TeamId: channel.TeamId,
|
||||
CallbackURLs: testCallBackURLs,
|
||||
Username: "some-user-name",
|
||||
IconURL: "http://some-website.com/assets/some-icon.png",
|
||||
DisplayName: "some-display-name",
|
||||
Description: "some-description",
|
||||
CreatorId: th.BasicUser.Id,
|
||||
TriggerWords: []string{"Abracadabra"},
|
||||
ContentType: "application/json",
|
||||
}
|
||||
|
||||
return th.App.CreateOutgoingWebhook(&outgoingWebhook)
|
||||
}
|
||||
|
||||
chanTs1 := make(chan string, 1)
|
||||
ts1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
chanTs1 <- "webhook received!"
|
||||
}))
|
||||
defer ts1.Close()
|
||||
|
||||
chanTs2 := make(chan string, 1)
|
||||
ts2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
chanTs2 <- "webhook received!"
|
||||
}))
|
||||
defer ts2.Close()
|
||||
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
*cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost,127.0.0.1"
|
||||
})
|
||||
|
||||
for name, testCase := range map[string]struct {
|
||||
CallBackURLs []string
|
||||
}{
|
||||
"One WebhookURL": {
|
||||
CallBackURLs: []string{ts1.URL},
|
||||
},
|
||||
"Two WebhookURLs": {
|
||||
CallBackURLs: []string{ts1.URL, ts2.URL},
|
||||
},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
*cfg.ServiceSettings.EnableOutgoingWebhooks = true
|
||||
})
|
||||
channel := th.CreateChannel(th.Context, th.BasicTeam)
|
||||
hook, _ := createOutgoingWebhook(channel, testCase.CallBackURLs, th)
|
||||
payload := getPayload(hook, th, channel)
|
||||
|
||||
th.App.TriggerWebhook(th.Context, payload, hook, th.BasicPost, channel)
|
||||
|
||||
select {
|
||||
case webhookResponse := <-chanTs1:
|
||||
require.Equal(t, "webhook received!", webhookResponse)
|
||||
|
||||
case <-time.After(5 * time.Second):
|
||||
require.Fail(t, "Timeout, webhook URL 1 response not received")
|
||||
}
|
||||
|
||||
if len(testCase.CallBackURLs) > 1 {
|
||||
select {
|
||||
case webhookResponse := <-chanTs2:
|
||||
require.Equal(t, "webhook received!", webhookResponse)
|
||||
|
||||
case <-time.After(5 * time.Second):
|
||||
require.Fail(t, "Timeout, webhook URL 2 response not received")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type InfiniteReader struct {
|
||||
Prefix string
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user