slacktest

package module
v0.0.0-...-c40012f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 26, 2019 License: MIT Imports: 12 Imported by: 0

README

slacktest

Deprecation notice

https://github.com/nlopes/slack has pulled in this repository and that's really for the best since it brings it closer to the code it's testing. Please use the library from here:

https://github.com/nlopes/slack/tree/master/slacktest

I'm honored that they did this and very sorry it took so long for me to realize that was the case.

Build Status

This is a very basic golang library for testing your slack RTM chatbots

Depending on your mechanism for building slackbots in go and how broken out your message parsing logic is, you can normally test that part pretty cleanly. However testing your bots RESPONSES are a bit harder.

This library attempts to make that a tad bit easier but in a slightly opinionated way.

The current most popular slack library for golang is nlopes/slack. Conviently the author has made overriding the slack API endpoint a feature. This allows us to use our fake slack server to inspect the chat process.

Limitations

Right now the test server is VERY limited. It currently handles the following API endpoints

  • rtm.start
  • chat.postMessage
  • channels.list
  • groups.list
  • users.info
  • bots.info

Additional endpoints are welcome.

Example usage

You can see an example in the examples directory of how to you might test it

If you just want to play around:

package main

import (
    "log"
    slacktest "github.com/lusis/slack-test"
    slackbot "github.com/lusis/go-slackbot"
    slack "github.com/nlopes/slack"
)

func globalMessageHandler(ctx context.Context, bot *slackbot.Bot, evt *slack.MessageEvent) {
    bot.Reply(evt, "I see your message", slackbot.WithoutTyping)
}

func main() {
    // Setup our test server
    s := slacktest.NewTestServer()
    // Set a custom name for our bot
    s.SetBotName("MyBotName")
    // ensure that anything using the slack api library uses our custom server
    slack.SLACK_API = "http://" + s.ServerAddr + "/"
    // start the test server
    go s.Start()
    // create a new slackbot. Token is irrelevant here
    bot := slackbot.New("ABCEDFG")
    // add a message handler
    bot.Hear("this is a channel message").MessageHandler(globalMessageHandler)
    // start the bot
    go bot.Run()
    //send a message to a channel
    s.SendMessageToChannel("#random", "this is a channel message")
    for m := range s.SeenFeed {
        log.Printf("saw message in slack: %s", m)
    }
}

Output:

# go run main.go
2017/09/26 10:53:49 {"type":"message","channel":"#random","text":"this is a channel message","ts":"1506437629","pinned_to":null}
2017/09/26 10:53:49 {"id":1,"channel":"#random","text":"I see your message","type":"message"}
#

You can see that our bot handled the message correctly.

Usage in tests

Currently it's not as ergonomic as I'd like. So much depends on how modular your bot code is in being able to run the same message handling code against a test instance. In the examples directory there are a couple of test cases.

Additionally, you definitely need to call time.Sleep for now in your test code to give time for the messages to work through the various channels and populate. I'd like to add a safer subscription mechanism in the future with a proper timeout mechanism.

If you want to, you can test the existing example in examples/go-slackbot:

# cd examples/go-slackbot
# go test -v
=== RUN   TestGlobalMessageHandler
--- PASS: TestGlobalMessageHandler (2.00s)
=== RUN   TestHelloMessageHandler
--- PASS: TestHelloMessageHandler (2.00s)
PASS
ok      github.com/lusis/slack-test/examples/go-slackbot        4.005s
#

testing an actual RTM session

This gets tricky. You can look at the existing rtm_test.go but here's a documented example:

package foo
import (
    "testing"
    "time"
    "github.com/nlopes/slack"
    "github.com/stretchr/testify/assert"
)

func TestRTMDirectMessage(t *testing.T) {
    // Let's skip this when we want short/quick tests
    if testing.Short() {
        t.Skip("skipping timered test")
    }
    // how long should we wait for this test to finish?
    maxWait := 5 * time.Second
    // start our test server
    s := NewTestServer()
    go s.Start()
    // set our slack API to the mock server
    slack.SLACK_API = s.GetAPIURL()
    api := slack.New("ABCDEFG")
    // rtm instance
    rtm := api.NewRTM()
    go rtm.ManageConnection()
    // create a channel to pass our results from the next goroutine
    // that is a goroutine doing the normal range over rtm.IncomingEvents
    messageChan := make(chan (*slack.MessageEvent), 1)
    go func() {
        for msg := range rtm.IncomingEvents {
            switch ev := msg.Data.(type) {
            case *slack.MessageEvent:
                messageChan <- ev
            }
        }
    }()
    // since we want to test direct messages, let's send one to the bot
    s.SendDirectMessageToBot(t.Name())
    // now we block this test
    select {
    // if we get a slack.MessageEvent, perform some assertions
    case m := <-messageChan:
        assert.Equal(t, "D024BE91L", m.Channel)
        assert.Equal(t, t.Name(), m.Text)
        break
    // if we hit our timeout, fail the test
    case <-time.After(maxWait):
        assert.FailNow(t, "did not get direct message in time")
    }
}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrEmptyServerToHub = fmt.Errorf("Unable to add an empty server address to hub")

ErrEmptyServerToHub is the error when attempting an empty server address to the hub

View Source
var ErrNoQueuesRegisteredForServer = fmt.Errorf("No queues registered for server")

ErrNoQueuesRegisteredForServer is the error when there are no queues for a server in the hub

View Source
var ErrPassedEmptyServerAddr = fmt.Errorf("Passed an empty server address")

ErrPassedEmptyServerAddr is the error when being passed an empty server address

View Source
var ServerBotChannelsContextKey contextKey = "__SERVER_CHANNELS__"

ServerBotChannelsContextKey is the list of channels associated with the fake server

View Source
var ServerBotGroupsContextKey contextKey = "__SERVER_GROUPS__"

ServerBotGroupsContextKey is the list of channels associated with the fake server

View Source
var ServerBotHubNameContextKey contextKey = "__SERVER_HUBNAME__"

ServerBotHubNameContextKey is the context key for passing along the server name registered in the hub

View Source
var ServerBotIDContextKey contextKey = "__SERVER_BOTID__"

ServerBotIDContextKey is the bot userid

View Source
var ServerBotNameContextKey contextKey = "__SERVER_BOTNAME__"

ServerBotNameContextKey is the bot name

View Source
var ServerURLContextKey contextKey = "__SERVER_URL__"

ServerURLContextKey is the context key to store the server's url

View Source
var ServerWSContextKey contextKey = "__SERVER_WS_URL__"

ServerWSContextKey is the context key to store the server's ws url

Functions

func BotIDFromContext

func BotIDFromContext(ctx context.Context) string

BotIDFromContext returns the bot userid from a provided context

func BotNameFromContext

func BotNameFromContext(ctx context.Context) string

BotNameFromContext returns the botname from a provided context

Types

type Server

type Server struct {
	Logger     *log.Logger
	BotName    string
	BotID      string
	ServerAddr string
	SeenFeed   chan (string)
	// contains filtered or unexported fields
}

Server represents a Slack Test server

func NewTestServer

func NewTestServer() *Server

NewTestServer returns a slacktest.Server ready to be started

func (*Server) GetAPIURL

func (sts *Server) GetAPIURL() string

GetAPIURL returns the api url you can pass to slack.SLACK_API

func (*Server) GetChannels

func (sts *Server) GetChannels() []slack.Channel

GetChannels returns all the fake channels registered

func (*Server) GetGroups

func (sts *Server) GetGroups() []slack.Group

GetGroups returns all the fake groups registered

func (*Server) GetSeenInboundMessages

func (sts *Server) GetSeenInboundMessages() []string

GetSeenInboundMessages returns all messages seen via websocket excluding pings

func (*Server) GetSeenOutboundMessages

func (sts *Server) GetSeenOutboundMessages() []string

GetSeenOutboundMessages returns all messages seen via websocket excluding pings

func (*Server) GetTestRTMInstance

func (sts *Server) GetTestRTMInstance() (*slack.Client, *slack.RTM)

GetTestRTMInstance will give you an RTM instance in the context of the current fake server

func (*Server) GetWSURL

func (sts *Server) GetWSURL() string

GetWSURL returns the websocket url

func (*Server) SawMessage

func (sts *Server) SawMessage(msg string) bool

SawMessage checks if an incoming message was seen

func (*Server) SawOutgoingMessage

func (sts *Server) SawOutgoingMessage(msg string) bool

SawOutgoingMessage checks if a message was sent to connected websocket clients

func (*Server) SendBotChannelInvite

func (sts *Server) SendBotChannelInvite()

SendBotChannelInvite invites the bot to a channel

func (*Server) SendBotGroupInvite

func (sts *Server) SendBotGroupInvite()

SendBotGroupInvite invites the bot to a channel

func (*Server) SendDirectMessageToBot

func (sts *Server) SendDirectMessageToBot(msg string)

SendDirectMessageToBot sends a direct message to the bot

func (*Server) SendMessageToBot

func (sts *Server) SendMessageToBot(channel, msg string)

SendMessageToBot sends a message addressed to the Bot

func (*Server) SendMessageToChannel

func (sts *Server) SendMessageToChannel(channel, msg string)

SendMessageToChannel sends a message to a channel

func (*Server) SendToWebsocket

func (sts *Server) SendToWebsocket(s string)

SendToWebsocket send `s` as is to connected clients. This is useful for sending your own custom json to the websocket

func (*Server) SetBotName

func (sts *Server) SetBotName(b string)

SetBotName sets a custom botname

func (*Server) Start

func (sts *Server) Start()

Start starts the test server

func (*Server) Stop

func (sts *Server) Stop()

Stop stops the test server

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL