2016-11-23 00:35:43 +00:00
|
|
|
package websocket
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2017-03-01 21:14:26 +00:00
|
|
|
"errors"
|
2016-11-23 00:35:43 +00:00
|
|
|
"fmt"
|
|
|
|
"net/http/httptest"
|
|
|
|
"net/url"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/gorilla/websocket"
|
2017-03-01 21:14:26 +00:00
|
|
|
|
2020-07-07 03:04:04 +00:00
|
|
|
"github.com/igm/sockjs-go/v3/sockjs"
|
2016-11-23 00:35:43 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
2017-03-01 21:14:26 +00:00
|
|
|
// readOpenMessage reads the sockjs open message
|
|
|
|
func readOpenMessage(t *testing.T, conn *websocket.Conn) {
|
|
|
|
// Read the open message
|
|
|
|
mType, data, err := conn.ReadMessage()
|
|
|
|
require.Equal(t, websocket.TextMessage, mType)
|
|
|
|
require.Nil(t, err)
|
2016-11-23 00:35:43 +00:00
|
|
|
|
2017-03-01 21:14:26 +00:00
|
|
|
require.Equal(t, []byte("o"), data, "expected sockjs open message")
|
|
|
|
}
|
2016-11-23 00:35:43 +00:00
|
|
|
|
2017-03-01 21:14:26 +00:00
|
|
|
// readJSONMessage reads a sockjs JSON message
|
|
|
|
func readJSONMessage(t *testing.T, conn *websocket.Conn) string {
|
|
|
|
mType, data, err := conn.ReadMessage()
|
|
|
|
require.Nil(t, err)
|
|
|
|
require.Equal(t, websocket.TextMessage, mType)
|
2016-11-23 00:35:43 +00:00
|
|
|
|
2017-03-01 21:14:26 +00:00
|
|
|
assert.Equal(t, "a", string(data[0]), "expected sockjs data frame")
|
2016-11-23 00:35:43 +00:00
|
|
|
|
2017-03-01 21:14:26 +00:00
|
|
|
// Unwrap from sockjs frame
|
|
|
|
d := []string{}
|
|
|
|
err = json.Unmarshal(data[1:], &d)
|
2016-11-23 00:35:43 +00:00
|
|
|
require.Nil(t, err)
|
2017-03-01 21:14:26 +00:00
|
|
|
require.Len(t, d, 1)
|
2016-11-23 00:35:43 +00:00
|
|
|
|
2017-03-01 21:14:26 +00:00
|
|
|
return d[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
func writeJSONMessage(t *testing.T, conn *websocket.Conn, typ string, data interface{}) {
|
|
|
|
buf, err := json.Marshal(JSONMessage{typ, data})
|
|
|
|
require.Nil(t, err)
|
|
|
|
|
|
|
|
// Wrap in sockjs frame
|
|
|
|
d, err := json.Marshal([]string{string(buf)})
|
|
|
|
require.Nil(t, err)
|
|
|
|
|
|
|
|
// Writes from the client to the server do not include the "a"
|
2022-12-05 22:50:49 +00:00
|
|
|
require.NoError(t, conn.WriteMessage(websocket.TextMessage, d))
|
2016-11-23 00:35:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestWriteJSONMessage(t *testing.T) {
|
2022-12-05 22:50:49 +00:00
|
|
|
cases := []struct {
|
2016-11-23 00:35:43 +00:00
|
|
|
typ string
|
|
|
|
data interface{}
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
typ: "string",
|
|
|
|
data: "some string",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
typ: "map",
|
|
|
|
data: map[string]string{"foo": "bar"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
typ: "struct",
|
|
|
|
data: struct {
|
|
|
|
Foo int `json:"foo"`
|
|
|
|
Bar string `json:"bar"`
|
|
|
|
}{
|
|
|
|
Foo: 16,
|
|
|
|
Bar: "baz",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range cases {
|
|
|
|
t.Run("", func(t *testing.T) {
|
2017-03-01 21:14:26 +00:00
|
|
|
handler := sockjs.NewHandler("/test", sockjs.DefaultOptions, func(session sockjs.Session) {
|
|
|
|
defer session.Close(0, "none")
|
|
|
|
|
|
|
|
conn := &Conn{session}
|
2016-11-23 00:35:43 +00:00
|
|
|
|
|
|
|
require.Nil(t, conn.WriteJSONMessage(tt.typ, tt.data))
|
2017-03-01 21:14:26 +00:00
|
|
|
})
|
2016-11-23 00:35:43 +00:00
|
|
|
|
2017-03-01 21:14:26 +00:00
|
|
|
srv := httptest.NewServer(handler)
|
2016-11-23 00:35:43 +00:00
|
|
|
u, _ := url.Parse(srv.URL)
|
|
|
|
u.Scheme = "ws"
|
2017-03-01 21:14:26 +00:00
|
|
|
u.Path += "/test/123/abcdefghijklmnop/websocket"
|
|
|
|
|
2016-11-23 00:35:43 +00:00
|
|
|
conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
|
|
|
|
require.Nil(t, err)
|
|
|
|
defer conn.Close()
|
2017-03-01 21:14:26 +00:00
|
|
|
readOpenMessage(t, conn)
|
2016-11-23 00:35:43 +00:00
|
|
|
|
|
|
|
dataJSON, err := json.Marshal(tt.data)
|
|
|
|
require.Nil(t, err)
|
|
|
|
|
|
|
|
// Ensure we read the correct message
|
2017-03-01 21:14:26 +00:00
|
|
|
data := readJSONMessage(t, conn)
|
2016-11-23 00:35:43 +00:00
|
|
|
assert.JSONEq(t,
|
|
|
|
fmt.Sprintf(`{"type": "%s", "data": %s}`, tt.typ, dataJSON),
|
2017-03-01 21:14:26 +00:00
|
|
|
data,
|
2016-11-23 00:35:43 +00:00
|
|
|
)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWriteJSONError(t *testing.T) {
|
2022-12-05 22:50:49 +00:00
|
|
|
cases := []struct {
|
2016-11-23 00:35:43 +00:00
|
|
|
err interface{}
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
err: "this is an error",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
err: struct {
|
|
|
|
Error string `json:"error"`
|
|
|
|
Extra map[string]string `json:"extra"`
|
|
|
|
}{
|
|
|
|
Error: "an error",
|
|
|
|
Extra: map[string]string{"foo": "bar"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range cases {
|
|
|
|
t.Run("", func(t *testing.T) {
|
2017-03-01 21:14:26 +00:00
|
|
|
handler := sockjs.NewHandler("/test", sockjs.DefaultOptions, func(session sockjs.Session) {
|
|
|
|
defer session.Close(0, "none")
|
|
|
|
|
|
|
|
conn := &Conn{session}
|
2016-11-23 00:35:43 +00:00
|
|
|
|
|
|
|
require.Nil(t, conn.WriteJSONError(tt.err))
|
2017-03-01 21:14:26 +00:00
|
|
|
})
|
2016-11-23 00:35:43 +00:00
|
|
|
|
2017-03-01 21:14:26 +00:00
|
|
|
srv := httptest.NewServer(handler)
|
2016-11-23 00:35:43 +00:00
|
|
|
u, _ := url.Parse(srv.URL)
|
|
|
|
u.Scheme = "ws"
|
2017-03-01 21:14:26 +00:00
|
|
|
u.Path += "/test/123/abcdefghijklmnop/websocket"
|
|
|
|
|
2016-11-23 00:35:43 +00:00
|
|
|
conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
|
|
|
|
require.Nil(t, err)
|
|
|
|
defer conn.Close()
|
2017-03-01 21:14:26 +00:00
|
|
|
readOpenMessage(t, conn)
|
2016-11-23 00:35:43 +00:00
|
|
|
|
|
|
|
errJSON, err := json.Marshal(tt.err)
|
|
|
|
require.Nil(t, err)
|
|
|
|
|
|
|
|
// Ensure we read the correct message
|
2017-03-01 21:14:26 +00:00
|
|
|
data := readJSONMessage(t, conn)
|
2016-11-23 00:35:43 +00:00
|
|
|
assert.JSONEq(t,
|
|
|
|
fmt.Sprintf(`{"type": "error", "data": %s}`, errJSON),
|
2017-03-01 21:14:26 +00:00
|
|
|
data,
|
2016-11-23 00:35:43 +00:00
|
|
|
)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestReadJSONMessage(t *testing.T) {
|
2022-12-05 22:50:49 +00:00
|
|
|
cases := []struct {
|
2016-11-23 00:35:43 +00:00
|
|
|
typ string
|
|
|
|
data interface{}
|
|
|
|
err error
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
typ: "string",
|
|
|
|
data: "some string",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
typ: "map",
|
|
|
|
data: map[string]string{"foo": "bar"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
typ: "struct",
|
|
|
|
data: struct {
|
|
|
|
Foo int `json:"foo"`
|
|
|
|
Bar string `json:"bar"`
|
|
|
|
}{
|
|
|
|
Foo: 16,
|
|
|
|
Bar: "baz",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
typ: "",
|
|
|
|
err: errors.New("missing message type"),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range cases {
|
|
|
|
t.Run("", func(t *testing.T) {
|
|
|
|
dataJSON, err := json.Marshal(tt.data)
|
|
|
|
require.Nil(t, err)
|
|
|
|
|
|
|
|
completed := make(chan struct{})
|
2017-03-01 21:14:26 +00:00
|
|
|
handler := sockjs.NewHandler("/test", sockjs.DefaultOptions, func(session sockjs.Session) {
|
|
|
|
defer session.Close(0, "none")
|
2016-11-23 00:35:43 +00:00
|
|
|
defer func() { completed <- struct{}{} }()
|
|
|
|
|
2017-03-01 21:14:26 +00:00
|
|
|
conn := &Conn{session}
|
2016-11-23 00:35:43 +00:00
|
|
|
|
|
|
|
msg, err := conn.ReadJSONMessage()
|
|
|
|
if tt.err == nil {
|
|
|
|
require.Nil(t, err)
|
|
|
|
} else {
|
|
|
|
require.Equal(t, tt.err.Error(), err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.Equal(t, tt.typ, msg.Type)
|
|
|
|
assert.EqualValues(t, &dataJSON, msg.Data)
|
2017-03-01 21:14:26 +00:00
|
|
|
})
|
2016-11-23 00:35:43 +00:00
|
|
|
|
|
|
|
// Connect to websocket handler server
|
2017-03-01 21:14:26 +00:00
|
|
|
srv := httptest.NewServer(handler)
|
2016-11-23 00:35:43 +00:00
|
|
|
u, _ := url.Parse(srv.URL)
|
|
|
|
u.Scheme = "ws"
|
2017-03-01 21:14:26 +00:00
|
|
|
u.Path += "/test/123/abcdefghijklmnop/websocket"
|
|
|
|
|
|
|
|
conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
|
2016-11-23 00:35:43 +00:00
|
|
|
require.Nil(t, err)
|
|
|
|
defer conn.Close()
|
|
|
|
|
2017-03-01 21:14:26 +00:00
|
|
|
readOpenMessage(t, conn)
|
|
|
|
|
|
|
|
writeJSONMessage(t, conn, tt.typ, tt.data)
|
2016-11-23 00:35:43 +00:00
|
|
|
|
|
|
|
select {
|
|
|
|
case <-completed:
|
|
|
|
// Normal
|
|
|
|
case <-time.After(1 * time.Second):
|
|
|
|
t.Error("handler did not complete")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestReadAuthToken(t *testing.T) {
|
2022-12-05 22:50:49 +00:00
|
|
|
cases := []struct {
|
2016-11-23 00:35:43 +00:00
|
|
|
typ string
|
|
|
|
data authData
|
2017-03-01 21:14:26 +00:00
|
|
|
token string
|
2016-11-23 00:35:43 +00:00
|
|
|
err error
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
typ: "auth",
|
|
|
|
data: authData{Token: "foobar"},
|
|
|
|
token: "foobar",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
typ: "auth",
|
|
|
|
data: authData{Token: ""},
|
|
|
|
token: "",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
typ: "string",
|
|
|
|
data: authData{Token: ""},
|
|
|
|
err: errors.New(`message type not "auth": "string"`),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range cases {
|
|
|
|
t.Run("", func(t *testing.T) {
|
|
|
|
completed := make(chan struct{})
|
2017-03-01 21:14:26 +00:00
|
|
|
handler := sockjs.NewHandler("/test", sockjs.DefaultOptions, func(session sockjs.Session) {
|
|
|
|
defer session.Close(0, "none")
|
2016-11-23 00:35:43 +00:00
|
|
|
defer func() { completed <- struct{}{} }()
|
|
|
|
|
2017-03-01 21:14:26 +00:00
|
|
|
conn := &Conn{session}
|
2016-11-23 00:35:43 +00:00
|
|
|
|
|
|
|
token, err := conn.ReadAuthToken()
|
|
|
|
if tt.err == nil {
|
|
|
|
require.Nil(t, err)
|
|
|
|
} else {
|
|
|
|
require.Equal(t, tt.err.Error(), err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-03-01 21:14:26 +00:00
|
|
|
assert.EqualValues(t, tt.token, token)
|
|
|
|
})
|
2016-11-23 00:35:43 +00:00
|
|
|
|
|
|
|
// Connect to websocket handler server
|
2017-03-01 21:14:26 +00:00
|
|
|
srv := httptest.NewServer(handler)
|
2016-11-23 00:35:43 +00:00
|
|
|
u, _ := url.Parse(srv.URL)
|
|
|
|
u.Scheme = "ws"
|
2017-03-01 21:14:26 +00:00
|
|
|
u.Path += "/test/123/abcdefghijklmnop/websocket"
|
|
|
|
|
|
|
|
conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
|
2016-11-23 00:35:43 +00:00
|
|
|
require.Nil(t, err)
|
|
|
|
defer conn.Close()
|
|
|
|
|
2017-03-01 21:14:26 +00:00
|
|
|
readOpenMessage(t, conn)
|
|
|
|
|
|
|
|
writeJSONMessage(t, conn, tt.typ, tt.data)
|
2016-11-23 00:35:43 +00:00
|
|
|
|
|
|
|
select {
|
|
|
|
case <-completed:
|
|
|
|
// Normal
|
|
|
|
case <-time.After(1 * time.Second):
|
|
|
|
t.Error("handler did not complete")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|