Skip to content

Commit

Permalink
Add utility function for validating slack integrations (#1114)
Browse files Browse the repository at this point in the history
  • Loading branch information
yorinasub17 committed May 5, 2022
1 parent 36cc060 commit 62f6d38
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 2 deletions.
1 change: 1 addition & 0 deletions .circleci/config.yml
Expand Up @@ -363,6 +363,7 @@ workflows:
- test:
context:
- Gruntwork Admin
- Slack Token For Test
requires:
- setup
filters:
Expand Down
5 changes: 4 additions & 1 deletion go.mod
Expand Up @@ -48,6 +48,8 @@ require (
k8s.io/client-go v0.20.6
)

require github.com/slack-go/slack v0.10.3

require (
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect
Expand All @@ -72,10 +74,11 @@ require (
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.3 // indirect
github.com/google/go-cmp v0.5.6 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
github.com/googleapis/gnostic v0.4.1 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
Expand Down
7 changes: 6 additions & 1 deletion go.sum
Expand Up @@ -354,6 +354,7 @@ github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZp
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M=
github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8=
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
Expand Down Expand Up @@ -419,8 +420,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-containerregistry v0.6.0 h1:niQ+8XD//kKgArIFwDVBXsWVWbde16LPdHMyNwSC8h4=
github.com/google/go-containerregistry v0.6.0/go.mod h1:euCCtNbZ6tKqi1E72vwDj2xZcN5ttKpZLfa/wSo5iLw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
Expand Down Expand Up @@ -461,6 +463,7 @@ github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
Expand Down Expand Up @@ -739,6 +742,8 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/slack-go/slack v0.10.3 h1:kKYwlKY73AfSrtAk9UHWCXXfitudkDztNI9GYBviLxw=
github.com/slack-go/slack v0.10.3/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
Expand Down
2 changes: 2 additions & 0 deletions modules/slack/doc.go
@@ -0,0 +1,2 @@
// Package slack contains routines useful for testing slack integrations.
package slack
98 changes: 98 additions & 0 deletions modules/slack/validate.go
@@ -0,0 +1,98 @@
package slack

import (
"fmt"
"strconv"
"strings"
"time"

"github.com/gruntwork-io/terratest/modules/testing"
"github.com/slack-go/slack"
)

// ValidateExpectedSlackMessage validates whether a message containing the expected text was posted in the given channel
// ID, looking back historyLimit messages up to the given duration. For example, if you set (15*time.Minute) as the
// lookBack parameter with historyLimit set to 50, then this will look back the last 50 messages, up to 15 minutes ago.
// This expects a slack token to be provided. This returns MessageNotFoundErr when there is no match.
// For the purposes of matching, this only checks the following blocks:
// - Section block text
// - Header block text
// All other blocks are ignored in the validation.
// NOTE: This only looks for bot posted messages.
func ValidateExpectedSlackMessageE(
t testing.TestingT,
token,
channelID,
expectedText string,
historyLimit int,
lookBack time.Duration,
) error {
lookBackTime := time.Now().Add(-1 * lookBack)
slackClt := slack.New(token)
params := slack.GetConversationHistoryParameters{
ChannelID: channelID,
Limit: historyLimit,
Oldest: strconv.FormatInt(lookBackTime.Unix(), 10),
}

resp, err := slackClt.GetConversationHistory(&params)
if err != nil {
return err
}

for _, msg := range resp.Messages {
if checkMessageContainsText(msg.Msg, expectedText) {
return nil
}

if msg.SubMessage != nil {
if checkMessageContainsText(*msg.SubMessage, expectedText) {
return nil
}
}
}
return fmt.Errorf("still no message")
}

func checkMessageContainsText(msg slack.Msg, expectedText string) bool {
// If this message is not a bot message, ignore.
if msg.Type != slack.MsgSubTypeBotMessage && msg.BotID == "" {
return false
}

// Check message text
if strings.Contains(msg.Text, expectedText) {
return true
}

// Check attachments
for _, attachment := range msg.Attachments {
if strings.Contains(attachment.Text, expectedText) {
return true
}
}

// Check blocks
for _, block := range msg.Blocks.BlockSet {
switch block.BlockType() {
case slack.MBTSection:
sectionBlk := block.(*slack.SectionBlock)
if sectionBlk.Text != nil && strings.Contains(sectionBlk.Text.Text, expectedText) {
return true
}
case slack.MBTHeader:
headerBlk := block.(*slack.HeaderBlock)
if headerBlk.Text != nil && strings.Contains(headerBlk.Text.Text, expectedText) {
return true
}
}
}

return false
}

type MessageNotFoundErr struct{}

func (err MessageNotFoundErr) Error() string {
return "Could not find the expected text in any of the messages posted in the given channel."
}
51 changes: 51 additions & 0 deletions modules/slack/validate_test.go
@@ -0,0 +1,51 @@
package slack

import (
"fmt"
"os"
"testing"
"time"

"github.com/slack-go/slack"
"github.com/stretchr/testify/require"

"github.com/gruntwork-io/terratest/modules/environment"
"github.com/gruntwork-io/terratest/modules/random"
"github.com/gruntwork-io/terratest/modules/retry"
)

const (
slackTokenEnv = "SLACK_TOKEN_FOR_TEST"
slackChannelIDEnv = "SLACK_CHANNEL_ID_FOR_TEST"
)

func TestValidateSlackMessage(t *testing.T) {
t.Parallel()

environment.RequireEnvVar(t, slackTokenEnv)
environment.RequireEnvVar(t, slackChannelIDEnv)

token := os.Getenv(slackTokenEnv)
channelID := os.Getenv(slackChannelIDEnv)

uniqueID := random.UniqueId()
msgTxt := fmt.Sprintf("Test message from terratest: %s", uniqueID)

slackClt := slack.New(token)

_, _, err := slackClt.PostMessage(
channelID,
slack.MsgOptionText(msgTxt, false),
)
require.NoError(t, err)

retry.DoWithRetry(
t,
"wait for slack message",
6, 10*time.Second,
func() (string, error) {
err := ValidateExpectedSlackMessageE(t, token, channelID, msgTxt, 10, 5*time.Minute)
return "", err
},
)
}

0 comments on commit 62f6d38

Please sign in to comment.