-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
client_test.go
128 lines (99 loc) · 3.2 KB
/
client_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package gateway
import (
"bytes"
"errors"
"fmt"
"github.com/discordpkg/gateway/closecode"
"strings"
"testing"
"time"
)
type NoopRateLimiter struct {
}
func (rl *NoopRateLimiter) Try(_ ShardID) (bool, time.Duration) {
return true, 0
}
type NopHeartbeatHandler struct{}
func (p *NopHeartbeatHandler) Configure(_ *StateCtx, _ time.Duration) {}
func (p *NopHeartbeatHandler) Run() {}
var commonOptions = []Option{
WithBotToken("token"),
WithCommandRateLimiter(&NoopRateLimiter{}),
WithIdentifyRateLimiter(&NoopRateLimiter{}),
WithHeartbeatHandler(&NopHeartbeatHandler{}),
}
func NewClientMust(t *testing.T, options ...Option) *Client {
client, err := NewClient(options...)
if err != nil {
t.Fatal(err)
}
return client
}
func TestCloseFrameHandling(t *testing.T) {
// The client supports processing the close code found in a websocket close frame. You can do this by creating a
// payload json with the close code and reason specified
options := append(commonOptions, []Option{}...)
description := "You sent more than one identify payload. Don't do that!"
data := fmt.Sprintf("{\"closecode\":%d,\"d\":\"%s\"}", closecode.AlreadyAuthenticated, description)
client := NewClientMust(t, options...)
client.ctx.SetState(&ConnectedState{client.ctx})
reader := strings.NewReader(data)
buffer := &bytes.Buffer{}
_, err := client.ProcessNext(reader, buffer)
if err == nil {
t.Fatal("missing error")
}
if got := buffer.String(); got != "" {
t.Error("client unexpectedly wrote to connection")
}
var discordErr *DiscordError
if !errors.As(err, &discordErr) {
t.Fatal("expected DiscordError type")
}
if discordErr.CloseCode != closecode.AlreadyAuthenticated {
t.Error("wrong close code")
}
if discordErr.Reason != description {
t.Errorf("wrong description. Got '%s', wants '%s'", discordErr.Reason, description)
}
}
func TestCloseFrameTransitions(t *testing.T) {
// The client supports processing the close code found in a websocket close frame. You can do this by creating a
// payload json with the close code and reason specified
options := append(commonOptions, []Option{}...)
description := "description"
resumeFrame := fmt.Sprintf("{\"closecode\":%d,\"d\":\"%s\"}", closecode.AlreadyAuthenticated, description)
closeFrame := fmt.Sprintf("{\"closecode\":%d,\"data\":\"%s\"}", closecode.ShardingRequired, description)
t.Run("close", func(t *testing.T) {
client, err := NewClient(options...)
if err != nil {
t.Fatal(err)
}
client.ctx.SetState(&ConnectedState{client.ctx})
reader := strings.NewReader(closeFrame)
buffer := &bytes.Buffer{}
_, err = client.ProcessNext(reader, buffer)
if err == nil {
t.Fatal("missing error")
}
if _, ok := client.ctx.state.(*ClosedState); !ok {
t.Error("expected state to be closed")
}
})
t.Run("resume", func(t *testing.T) {
client, err := NewClient(options...)
if err != nil {
t.Fatal(err)
}
client.ctx.SetState(&ConnectedState{client.ctx})
reader := strings.NewReader(resumeFrame)
buffer := &bytes.Buffer{}
_, err = client.ProcessNext(reader, buffer)
if err == nil {
t.Fatal("missing error")
}
if _, ok := client.ctx.state.(*ResumableClosedState); !ok {
t.Error("expected state to be resumable")
}
})
}