From c675dd329a39dc0852e20b66e7aa6753ea440a87 Mon Sep 17 00:00:00 2001 From: Ezo Saleh <105397+ezodude@users.noreply.github.com> Date: Wed, 28 Sep 2022 11:32:39 +0100 Subject: [PATCH] Added E2E test to verify large output is received as plaintext file with executor command as message. --- test/e2e/bots_test.go | 32 ++++++++++++++++----- test/e2e/bots_tester_test.go | 2 ++ test/e2e/discord_driver_test.go | 51 +++++++++++++++++++++++++++++++++ test/e2e/slack_driver_test.go | 46 +++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 7 deletions(-) diff --git a/test/e2e/bots_test.go b/test/e2e/bots_test.go index d5fa7c264a..a5757df5c2 100644 --- a/test/e2e/bots_test.go +++ b/test/e2e/bots_test.go @@ -66,12 +66,13 @@ type DiscordConfig struct { } const ( - channelNamePrefix = "test" - welcomeText = "Let the tests begin 🤞" - pollInterval = time.Second - slackAnnotation = "" - discordAnnotation = "botkube.io/*" - discordInvalidCmd = "You must specify the type of resource to get. Use \"kubectl api-resources\" for a complete list of supported resources.\n\nerror: Required resource not specified.\nUse \"kubectl explain \" for a detailed description of that resource (e.g. kubectl explain pods).\nSee 'kubectl get -h' for help and examples\nexit status 1" + channelNamePrefix = "test" + welcomeText = "Let the tests begin 🤞" + pollInterval = time.Second + globalConfigMapName = "botkube-global-config" + slackAnnotation = "" + discordAnnotation = "botkube.io/*" + discordInvalidCmd = "You must specify the type of resource to get. Use \"kubectl api-resources\" for a complete list of supported resources.\n\nerror: Required resource not specified.\nUse \"kubectl explain \" for a detailed description of that resource (e.g. kubectl explain pods).\nSee 'kubectl get -h' for help and examples\nexit status 1" ) var ( @@ -170,12 +171,14 @@ func runBotTest(t *testing.T, err = waitForDeploymentReady(deployNsCli, appCfg.Deployment.Name, appCfg.Deployment.WaitTimeout) require.NoError(t, err) - t.Log("Waiting for Bot message in channel...") + t.Log("Waiting for interactive help") err = botDriver.WaitForInteractiveMessagePostedRecentlyEqual(botDriver.BotUserID(), botDriver.Channel().ID(), interactive.Help(config.CommPlatformIntegration(botDriver.Type()), appCfg.ClusterName, botDriver.BotName()), ) require.NoError(t, err) + + t.Log("Waiting for Bot message in channel...") err = botDriver.WaitForMessagePostedRecentlyEqual(botDriver.BotUserID(), botDriver.Channel().ID(), fmt.Sprintf("...and now my watch begins for cluster '%s'! :crossed_swords:", appCfg.ClusterName)) require.NoError(t, err) @@ -330,6 +333,21 @@ func runBotTest(t *testing.T, assert.NoError(t, err) }) + t.Run("Receive large output as plaintext file with executor command as message", func(t *testing.T) { + command := fmt.Sprintf("get configmap %s -o yaml -n %s", globalConfigMapName, appCfg.Deployment.Namespace) + fileUploadAssertionFn := func(title, mimetype string) bool { + return title == "Response.txt" && strings.Contains(mimetype, "text/plain") + } + botDriver.PostMessageToBot(t, botDriver.Channel().Identifier(), command) + err = botDriver.WaitForMessagePostedWithFileUpload(botDriver.BotUserID(), botDriver.Channel().ID(), fileUploadAssertionFn) + assert.NoError(t, err) + + assertionFn := func(msg string) bool { + return strings.Contains(msg, heredoc.Doc(fmt.Sprintf("`%s` on `%s`", command, appCfg.ClusterName))) + } + err = botDriver.WaitForMessagePosted(botDriver.BotUserID(), botDriver.Channel().ID(), 1, assertionFn) + }) + t.Run("Get forbidden resource", func(t *testing.T) { command := "get ingress" expectedBody := codeBlock(fmt.Sprintf("Sorry, the kubectl command is not authorized to work with 'ingress' resources in the 'default' Namespace on cluster '%s'. Use 'commands list' to see allowed commands.", appCfg.ClusterName)) diff --git a/test/e2e/bots_tester_test.go b/test/e2e/bots_tester_test.go index 54667d1dd8..a1d5d331fa 100644 --- a/test/e2e/bots_tester_test.go +++ b/test/e2e/bots_tester_test.go @@ -24,6 +24,7 @@ var structDumper = litter.Options{ type MessageAssertion func(content string) bool type AttachmentAssertion func(title, color, msg string) bool +type FileUploadAssertion func(title, mimetype string) bool type Channel interface { ID() string @@ -53,6 +54,7 @@ type BotDriver interface { WaitForLastMessageEqual(userID, channel, expectedMsg string) error WaitForMessagePosted(userID, channel string, limitMessages int, assertFn MessageAssertion) error WaitForInteractiveMessagePosted(userID, channelID string, limitMessages int, assertFn MessageAssertion) error + WaitForMessagePostedWithFileUpload(userID, channelID string, assertFn FileUploadAssertion) error WaitForMessagePostedWithAttachment(userID, channel string, assertFn AttachmentAssertion) error WaitForMessagesPostedOnChannelsWithAttachment(userID string, channelIDs []string, assertFn AttachmentAssertion) error Channel() Channel diff --git a/test/e2e/discord_driver_test.go b/test/e2e/discord_driver_test.go index 1f785aefb2..a2ce3abfc7 100644 --- a/test/e2e/discord_driver_test.go +++ b/test/e2e/discord_driver_test.go @@ -189,6 +189,57 @@ func (d *discordTester) WaitForInteractiveMessagePosted(userID, channelID string return d.WaitForMessagePosted(userID, channelID, limitMessages, assertFn) } +func (d *discordTester) WaitForMessagePostedWithFileUpload(userID, channelID string, assertFn FileUploadAssertion) error { + // To always receive message content: + // ensure you enable the MESSAGE CONTENT INTENT for the tester bot on the developer portal. + // Applications ↦ Settings ↦ Bot ↦ Privileged Gateway Intents + // This setting has been enforced from August 31, 2022 + + var fetchedMessages []*discordgo.Message + var lastErr error + + err := wait.Poll(pollInterval, d.cfg.MessageWaitTimeout, func() (done bool, err error) { + messages, err := d.cli.ChannelMessages(channelID, 1, "", "", "") + if err != nil { + lastErr = err + return false, nil + } + + fetchedMessages = messages + for _, msg := range messages { + if msg.Author.ID != userID { + continue + } + + if len(msg.Attachments) != 1 { + lastErr = err + return false, nil + } + + upload := msg.Attachments[0] + if !assertFn(upload.Filename, upload.ContentType) { + // different message + continue + } + + return true, nil + } + + return false, nil + }) + if lastErr == nil { + lastErr = errors.New("message assertion function returned false") + } + if err != nil { + if err == wait.ErrWaitTimeout { + return fmt.Errorf("while waiting for condition: last error: %w; fetched messages: %s", lastErr, structDumper.Sdump(fetchedMessages)) + } + return err + } + + return nil +} + func (d *discordTester) WaitForMessagePostedWithAttachment(userID, channelID string, assertFn AttachmentAssertion) error { // To always receive message content: // ensure you enable the MESSAGE CONTENT INTENT for the tester bot on the developer portal. diff --git a/test/e2e/slack_driver_test.go b/test/e2e/slack_driver_test.go index 2170b96b4e..8e4d2363f5 100644 --- a/test/e2e/slack_driver_test.go +++ b/test/e2e/slack_driver_test.go @@ -187,6 +187,52 @@ func (s *slackTester) WaitForInteractiveMessagePosted(userID, channelID string, return s.WaitForMessagePosted(userID, channelID, limitMessages, assertFn) } +func (s *slackTester) WaitForMessagePostedWithFileUpload(userID, channelID string, assertFn FileUploadAssertion) error { + var fetchedMessages []slack.Message + var lastErr error + err := wait.Poll(pollInterval, s.cfg.MessageWaitTimeout, func() (done bool, err error) { + historyRes, err := s.cli.GetConversationHistory(&slack.GetConversationHistoryParameters{ + ChannelID: channelID, Limit: 1, + }) + if err != nil { + lastErr = err + return false, nil + } + + fetchedMessages = historyRes.Messages + for _, msg := range historyRes.Messages { + if msg.User != userID { + continue + } + + if len(msg.Files) != 1 { + return false, nil + } + + upload := msg.Files[0] + if !assertFn(upload.Title, upload.Mimetype) { + // different message + return false, nil + } + + return true, nil + } + + return false, nil + }) + if lastErr == nil { + lastErr = errors.New("message assertion function returned false") + } + if err != nil { + if err == wait.ErrWaitTimeout { + return fmt.Errorf("while waiting for condition: last error: %w; fetched messages: %s", lastErr, structDumper.Sdump(fetchedMessages)) + } + return err + } + + return nil +} + func (s *slackTester) WaitForMessagePostedWithAttachment(userID, channelID string, assertFn AttachmentAssertion) error { var fetchedMessages []slack.Message var lastErr error