Skip to content

Commit

Permalink
Merge pull request #1086 from mszostok/unmapped-typed-err
Browse files Browse the repository at this point in the history
Add option to detect unmapped error
  • Loading branch information
kanata2 committed Jul 21, 2022
2 parents a8b9f28 + 9e4de8b commit 5a6b1b0
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 1 deletion.
27 changes: 26 additions & 1 deletion websocket_managed_conn.go
Expand Up @@ -16,6 +16,31 @@ import (
"github.com/slack-go/slack/internal/timex"
)

// UnmappedError represents error occurred when there is no mapping between given event name
// and corresponding Go struct.
type UnmappedError struct {
// EventType returns event type name.
EventType string
// RawEvent returns raw event body.
RawEvent json.RawMessage

ctxMsg string
}

// NewUnmappedError returns new UnmappedError instance.
func NewUnmappedError(ctxMsg, eventType string, raw json.RawMessage) *UnmappedError {
return &UnmappedError{
ctxMsg: ctxMsg,
EventType: eventType,
RawEvent: raw,
}
}

// Error returns human-readable error message.
func (u UnmappedError) Error() string {
return fmt.Sprintf("%s: Received unmapped event %q", u.ctxMsg, u.EventType)
}

// ManageConnection can be called on a Slack RTM instance returned by the
// NewRTM method. It will connect to the slack RTM API and handle all incoming
// and outgoing events. If a connection fails then it will attempt to reconnect
Expand Down Expand Up @@ -474,7 +499,7 @@ func (rtm *RTM) handleEvent(typeStr string, event json.RawMessage) {
v, exists := EventMapping[typeStr]
if !exists {
rtm.Debugf("RTM Error - received unmapped event %q: %s\n", typeStr, string(event))
err := fmt.Errorf("RTM Error: Received unmapped event %q", typeStr)
err := NewUnmappedError("RTM Error", typeStr, event)
rtm.IncomingEvents <- RTMEvent{"unmarshalling_error", &UnmarshallingErrorEvent{err}}
return
}
Expand Down
60 changes: 60 additions & 0 deletions websocket_managed_conn_test.go
@@ -1,6 +1,7 @@
package slack_test

import (
"encoding/json"
"fmt"
"log"
"net/http"
Expand All @@ -9,6 +10,7 @@ import (

websocket "github.com/gorilla/websocket"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/slack-go/slack"
"github.com/slack-go/slack/slacktest"
Expand Down Expand Up @@ -313,3 +315,61 @@ func TestRTMSingleConnect(t *testing.T) {
assert.True(t, connectedReceived, "Should have received a connected event from the RTM instance.")
assert.True(t, testMessageReceived, "Should have received a test message from the server.")
}

func TestRTMUnmappedError(t *testing.T) {
const unmappedEventName = "user_status_changed"
// Set up the test server.
testServer := slacktest.NewTestServer()
go testServer.Start()

// Setup and start the RTM.
api := slack.New(testToken, slack.OptionAPIURL(testServer.GetAPIURL()))
rtm := api.NewRTM()
go rtm.ManageConnection()

// Observe incoming messages.
done := make(chan struct{})
var gotUnmarshallingError *slack.UnmarshallingErrorEvent
go func() {
for msg := range rtm.IncomingEvents {
switch ev := msg.Data.(type) {
case *slack.UnmarshallingErrorEvent:
gotUnmarshallingError = ev
rtm.Disconnect()
case *slack.DisconnectedEvent:
if ev.Intentional {
done <- struct{}{}
return
}
default:
t.Logf("Discarded event of type '%s' with content '%#v'", msg.Type, ev)
}
}
}()

// Send a message and sleep for some time to make sure the message can be processed client-side.
testServer.SendToWebsocket(fixSlackMessage(t, unmappedEventName))
<-done
testServer.Stop()

// Verify that we got the expected error with details
unmappedErr, ok := gotUnmarshallingError.ErrorObj.(*slack.UnmappedError)
require.True(t, ok)
assert.Equal(t, unmappedEventName, unmappedErr.EventType)
}

func fixSlackMessage(t *testing.T, eType string) string {
t.Helper()

m := slack.Message{
Msg: slack.Msg{
Type: eType,
Text: "Fixture Slack message",
Timestamp: fmt.Sprintf("%d", time.Now().Unix()),
},
}
msg, err := json.Marshal(m)
require.NoError(t, err)

return string(msg)
}

0 comments on commit 5a6b1b0

Please sign in to comment.