From 21a3219b9b1df033635631afa751742bd4c56ea0 Mon Sep 17 00:00:00 2001 From: Saturnino Abril Date: Wed, 19 Jul 2017 03:43:31 +0800 Subject: [PLT-6676] Make OutgoingWebhook to fire when post has no text content but only attachment (#6935) * make OutgoingWebhook to fire when post has no text content but only attachment * update per comment and modify payload & test --- api4/post_test.go | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) (limited to 'api4/post_test.go') diff --git a/api4/post_test.go b/api4/post_test.go index a2c0b065b..d554ca472 100644 --- a/api4/post_test.go +++ b/api4/post_test.go @@ -4,9 +4,13 @@ package api4 import ( + "encoding/json" "net/http" + "net/http/httptest" + "net/url" "reflect" "strconv" + "strings" "testing" "time" @@ -101,6 +105,158 @@ func TestCreatePost(t *testing.T) { } } +func testCreatePostWithOutgoingHook( + t *testing.T, + hookContentType, expectedContentType, message, triggerWord string, + fileIds []string, + triggerWhen int, +) { + th := Setup().InitBasic().InitSystemAdmin() + defer TearDown() + user := th.SystemAdminUser + team := th.BasicTeam + channel := th.BasicChannel + + enableOutgoingHooks := utils.Cfg.ServiceSettings.EnableOutgoingWebhooks + enableAdminOnlyHooks := utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations + defer func() { + utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = enableOutgoingHooks + utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = enableAdminOnlyHooks + utils.SetDefaultRolesBasedOnConfig() + }() + utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = true + *utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = true + utils.SetDefaultRolesBasedOnConfig() + + var hook *model.OutgoingWebhook + var post *model.Post + + // Create a test server that is the target of the outgoing webhook. It will + // validate the webhook body fields and write to the success channel on + // success/failure. + success := make(chan bool) + wait := make(chan bool, 1) + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + <-wait + + requestContentType := r.Header.Get("Content-Type") + if requestContentType != expectedContentType { + t.Logf("Content-Type is %s, should be %s", requestContentType, expectedContentType) + success <- false + return + } + + expectedPayload := &model.OutgoingWebhookPayload{ + Token: hook.Token, + TeamId: hook.TeamId, + TeamDomain: team.Name, + ChannelId: post.ChannelId, + ChannelName: channel.Name, + Timestamp: post.CreateAt, + UserId: post.UserId, + UserName: user.Username, + PostId: post.Id, + Text: post.Message, + TriggerWord: triggerWord, + FileIds: strings.Join(post.FileIds, ","), + } + + // depending on the Content-Type, we expect to find a JSON or form encoded payload + if requestContentType == "application/json" { + decoder := json.NewDecoder(r.Body) + o := &model.OutgoingWebhookPayload{} + decoder.Decode(&o) + + if !reflect.DeepEqual(expectedPayload, o) { + t.Logf("JSON payload is %+v, should be %+v", o, expectedPayload) + success <- false + return + } + } else { + err := r.ParseForm() + if err != nil { + t.Logf("Error parsing form: %q", err) + success <- false + return + } + + expectedFormValues, _ := url.ParseQuery(expectedPayload.ToFormValues()) + if !reflect.DeepEqual(expectedFormValues, r.Form) { + t.Logf("Form values are: %q\n, should be: %q\n", r.Form, expectedFormValues) + success <- false + return + } + } + + success <- true + })) + defer ts.Close() + + // create an outgoing webhook, passing it the test server URL + var triggerWords []string + if triggerWord != "" { + triggerWords = []string{triggerWord} + } + + hook = &model.OutgoingWebhook{ + ChannelId: channel.Id, + TeamId: team.Id, + ContentType: hookContentType, + TriggerWords: triggerWords, + TriggerWhen: triggerWhen, + CallbackURLs: []string{ts.URL}, + } + + hook, resp := th.SystemAdminClient.CreateOutgoingWebhook(hook) + CheckNoError(t, resp) + + // create a post to trigger the webhook + post = &model.Post{ + ChannelId: channel.Id, + Message: message, + FileIds: fileIds, + } + + post, resp = th.SystemAdminClient.CreatePost(post) + CheckNoError(t, resp) + + wait <- true + + // We wait for the test server to write to the success channel and we make + // the test fail if that doesn't happen before the timeout. + select { + case ok := <-success: + if !ok { + t.Fatal("Test server did send an invalid webhook.") + } + case <-time.After(time.Second): + t.Fatal("Timeout, test server did not send the webhook.") + } +} + +func TestCreatePostWithOutgoingHook_form_urlencoded(t *testing.T) { + testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH) + testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH) + testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "", "", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH) + testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH) +} + +func TestCreatePostWithOutgoingHook_json(t *testing.T) { + testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH) + testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_STARTS_WITH) + testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH) + testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH) +} + +// hooks created before we added the ContentType field should be considered as +// application/x-www-form-urlencoded +func TestCreatePostWithOutgoingHook_no_content_type(t *testing.T) { + testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH) + testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH) + testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH) + testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_STARTS_WITH) +} + func TestUpdatePost(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer TearDown() -- cgit v1.2.3-1-g7c22