good morning!!!!

Skip to content
Snippets Groups Projects
Unverified Commit ff4d818b authored by Anmol Sethi's avatar Anmol Sethi
Browse files

Add WASM test

parent 599534b9
No related branches found
No related tags found
No related merge requests found
package websocket_test package websocket_test
import ( import (
"context"
"fmt"
"reflect" "reflect"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"nhooyr.io/websocket"
"nhooyr.io/websocket/wsjson"
) )
// https://github.com/google/go-cmp/issues/40#issuecomment-328615283 // https://github.com/google/go-cmp/issues/40#issuecomment-328615283
...@@ -51,3 +56,44 @@ func structTypes(v reflect.Value, m map[reflect.Type]struct{}) { ...@@ -51,3 +56,44 @@ func structTypes(v reflect.Value, m map[reflect.Type]struct{}) {
} }
} }
} }
func assertEqualf(exp, act interface{}, f string, v ...interface{}) error {
if diff := cmpDiff(exp, act); diff != "" {
return fmt.Errorf(f+": %v", append(v, diff)...)
}
return nil
}
func assertJSONEcho(ctx context.Context, c *websocket.Conn, n int) error {
exp := randString(n)
err := wsjson.Write(ctx, c, exp)
if err != nil {
return err
}
var act interface{}
err = wsjson.Read(ctx, c, &act)
if err != nil {
return err
}
return assertEqualf(exp, act, "unexpected JSON")
}
func assertJSONRead(ctx context.Context, c *websocket.Conn, exp interface{}) error {
var act interface{}
err := wsjson.Read(ctx, c, &act)
if err != nil {
return err
}
return assertEqualf(exp, act, "unexpected JSON")
}
func randBytes(n int) []byte {
return make([]byte, n)
}
func randString(n int) string {
return string(randBytes(n))
}
...@@ -6,7 +6,14 @@ set -euo pipefail ...@@ -6,7 +6,14 @@ set -euo pipefail
cd "$(dirname "${0}")" cd "$(dirname "${0}")"
cd "$(git rev-parse --show-toplevel)" cd "$(git rev-parse --show-toplevel)"
echo "--- fmt"
./ci/fmt.sh ./ci/fmt.sh
echo "--- lint"
./ci/lint.sh ./ci/lint.sh
echo "--- test"
./ci/test.sh ./ci/test.sh
echo "--- wasm"
./ci/wasm.sh ./ci/wasm.sh
...@@ -16,9 +16,13 @@ if [[ ${CI-} ]]; then ...@@ -16,9 +16,13 @@ if [[ ${CI-} ]]; then
) )
fi fi
if [[ $# -gt 0 ]]; then
argv+=( argv+=(
"$@" "$@"
) )
else
argv+=(./...)
fi
mkdir -p ci/out/websocket mkdir -p ci/out/websocket
"${argv[@]}" "${argv[@]}"
......
...@@ -4,7 +4,13 @@ set -euo pipefail ...@@ -4,7 +4,13 @@ set -euo pipefail
cd "$(dirname "${0}")" cd "$(dirname "${0}")"
cd "$(git rev-parse --show-toplevel)" cd "$(git rev-parse --show-toplevel)"
stdout="$(mktemp -d)/stdout"
mkfifo "$stdout"
go run ./internal/wsecho/cmd > "$stdout" &
WS_ECHO_SERVER_URL="$(head -n 1 "$stdout")"
GOOS=js GOARCH=wasm go vet ./... GOOS=js GOARCH=wasm go vet ./...
go install golang.org/x/lint/golint go install golang.org/x/lint/golint
GOOS=js GOARCH=wasm golint -set_exit_status ./... GOOS=js GOARCH=wasm golint -set_exit_status ./...
GOOS=js GOARCH=wasm go test ./... GOOS=js GOARCH=wasm go test ./... -args "$WS_ECHO_SERVER_URL"
package echoserver
import (
"net/http"
)
// EchoServer provides a streaming WebSocket echo server
// for use in tests.
func EchoServer(w http.ResponseWriter, r *http.Request) {
}
// +build !js
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"runtime"
"strings"
"nhooyr.io/websocket/internal/wsecho"
)
func main() {
s := httptest.NewServer(http.HandlerFunc(wsecho.Serve))
wsURL := strings.Replace(s.URL, "http", "ws", 1)
fmt.Printf("%v\n", wsURL)
runtime.Goexit()
}
// +build !js
package wsecho
import (
"context"
"io"
"log"
"net/http"
"time"
"nhooyr.io/websocket"
)
// Serve provides a streaming WebSocket echo server
// for use in tests.
func Serve(w http.ResponseWriter, r *http.Request) {
c, err := websocket.Accept(w, r, &websocket.AcceptOptions{
Subprotocols: []string{"echo"},
InsecureSkipVerify: true,
})
if err != nil {
log.Printf("echo server: failed to accept: %+v", err)
return
}
defer c.Close(websocket.StatusInternalError, "")
Loop(r.Context(), c)
}
// Loop echos every msg received from c until an error
// occurs or the context expires.
// The read limit is set to 1 << 40.
func Loop(ctx context.Context, c *websocket.Conn) {
defer c.Close(websocket.StatusInternalError, "")
c.SetReadLimit(1 << 40)
ctx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
b := make([]byte, 32768)
echo := func() error {
typ, r, err := c.Reader(ctx)
if err != nil {
return err
}
w, err := c.Writer(ctx, typ)
if err != nil {
return err
}
_, err = io.CopyBuffer(w, r, b)
if err != nil {
return err
}
err = w.Close()
if err != nil {
return err
}
return nil
}
for {
err := echo()
if err != nil {
return
}
}
}
...@@ -20,6 +20,8 @@ import ( ...@@ -20,6 +20,8 @@ import (
"strings" "strings"
"testing" "testing"
"time" "time"
"nhooyr.io/websocket/internal/wsecho"
) )
// https://github.com/crossbario/autobahn-python/tree/master/wstest // https://github.com/crossbario/autobahn-python/tree/master/wstest
...@@ -34,7 +36,7 @@ func TestPythonAutobahnServer(t *testing.T) { ...@@ -34,7 +36,7 @@ func TestPythonAutobahnServer(t *testing.T) {
t.Logf("server handshake failed: %+v", err) t.Logf("server handshake failed: %+v", err)
return return
} }
echoLoop(r.Context(), c) wsecho.Loop(r.Context(), c)
})) }))
defer s.Close() defer s.Close()
...@@ -186,7 +188,7 @@ func TestPythonAutobahnClientOld(t *testing.T) { ...@@ -186,7 +188,7 @@ func TestPythonAutobahnClientOld(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
echoLoop(ctx, c) wsecho.Loop(ctx, c)
}() }()
} }
......
...@@ -13,6 +13,7 @@ import ( ...@@ -13,6 +13,7 @@ import (
"time" "time"
"nhooyr.io/websocket" "nhooyr.io/websocket"
"nhooyr.io/websocket/internal/wsecho"
) )
func BenchmarkConn(b *testing.B) { func BenchmarkConn(b *testing.B) {
...@@ -54,7 +55,7 @@ func benchConn(b *testing.B, echo, stream bool, size int) { ...@@ -54,7 +55,7 @@ func benchConn(b *testing.B, echo, stream bool, size int) {
return err return err
} }
if echo { if echo {
echoLoop(r.Context(), c) wsecho.Loop(r.Context(), c)
} else { } else {
discardLoop(r.Context(), c) discardLoop(r.Context(), c)
} }
......
...@@ -59,7 +59,7 @@ func (c *Conn) init() { ...@@ -59,7 +59,7 @@ func (c *Conn) init() {
}) })
runtime.SetFinalizer(c, func(c *Conn) { runtime.SetFinalizer(c, func(c *Conn) {
c.ws.Close(int(StatusInternalError), "internal error") c.ws.Close(int(StatusInternalError), "")
c.close(errors.New("connection garbage collected")) c.close(errors.New("connection garbage collected"))
}) })
} }
...@@ -133,12 +133,10 @@ func (c *Conn) Close(code StatusCode, reason string) error { ...@@ -133,12 +133,10 @@ func (c *Conn) Close(code StatusCode, reason string) error {
return fmt.Errorf("already closed: %w", c.closeErr) return fmt.Errorf("already closed: %w", c.closeErr)
} }
cerr := CloseError{ err := fmt.Errorf("sent close frame: %v", CloseError{
Code: code, Code: code,
Reason: reason, Reason: reason,
} })
err := fmt.Errorf("sent close frame: %v", cerr)
err2 := c.ws.Close(int(code), reason) err2 := c.ws.Close(int(code), reason)
if err2 != nil { if err2 != nil {
...@@ -146,7 +144,7 @@ func (c *Conn) Close(code StatusCode, reason string) error { ...@@ -146,7 +144,7 @@ func (c *Conn) Close(code StatusCode, reason string) error {
} }
c.close(err) c.close(err)
if !xerrors.Is(c.closeErr, cerr) { if !xerrors.Is(c.closeErr, err) {
return xerrors.Errorf("failed to close websocket: %w", err) return xerrors.Errorf("failed to close websocket: %w", err)
} }
......
...@@ -2,19 +2,40 @@ package websocket_test ...@@ -2,19 +2,40 @@ package websocket_test
import ( import (
"context" "context"
"net/http"
"os"
"testing" "testing"
"time" "time"
"nhooyr.io/websocket" "nhooyr.io/websocket"
) )
var wsEchoServerURL = os.Args[1]
func TestWebSocket(t *testing.T) { func TestWebSocket(t *testing.T) {
t.Parallel() t.Parallel()
_, _, err := websocket.Dial(context.Background(), "ws://localhost:8081", nil) ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
c, resp, err := websocket.Dial(ctx, wsEchoServerURL, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer c.Close(websocket.StatusInternalError, "")
time.Sleep(time.Second) err = assertEqualf(&http.Response{}, resp, "unexpected http response")
if err != nil {
t.Fatal(err)
}
err = assertJSONEcho(ctx, c, 4096)
if err != nil {
t.Fatal(err)
}
err = c.Close(websocket.StatusNormalClosure, "")
if err != nil {
t.Fatal(err)
}
} }
...@@ -29,6 +29,7 @@ import ( ...@@ -29,6 +29,7 @@ import (
"go.uber.org/multierr" "go.uber.org/multierr"
"nhooyr.io/websocket" "nhooyr.io/websocket"
"nhooyr.io/websocket/internal/wsecho"
"nhooyr.io/websocket/wsjson" "nhooyr.io/websocket/wsjson"
"nhooyr.io/websocket/wspb" "nhooyr.io/websocket/wspb"
) )
...@@ -966,7 +967,7 @@ func TestAutobahn(t *testing.T) { ...@@ -966,7 +967,7 @@ func TestAutobahn(t *testing.T) {
ctx := r.Context() ctx := r.Context()
if testingClient { if testingClient {
echoLoop(r.Context(), c) wsecho.Loop(r.Context(), c)
return nil return nil
} }
...@@ -1007,7 +1008,7 @@ func TestAutobahn(t *testing.T) { ...@@ -1007,7 +1008,7 @@ func TestAutobahn(t *testing.T) {
return return
} }
echoLoop(ctx, c) wsecho.Loop(ctx, c)
} }
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
t.Parallel() t.Parallel()
...@@ -1849,47 +1850,6 @@ func TestAutobahn(t *testing.T) { ...@@ -1849,47 +1850,6 @@ func TestAutobahn(t *testing.T) {
}) })
} }
func echoLoop(ctx context.Context, c *websocket.Conn) {
defer c.Close(websocket.StatusInternalError, "")
c.SetReadLimit(1 << 40)
ctx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
b := make([]byte, 32768)
echo := func() error {
typ, r, err := c.Reader(ctx)
if err != nil {
return err
}
w, err := c.Writer(ctx, typ)
if err != nil {
return err
}
_, err = io.CopyBuffer(w, r, b)
if err != nil {
return err
}
err = w.Close()
if err != nil {
return err
}
return nil
}
for {
err := echo()
if err != nil {
return
}
}
}
func assertCloseStatus(err error, code websocket.StatusCode) error { func assertCloseStatus(err error, code websocket.StatusCode) error {
var cerr websocket.CloseError var cerr websocket.CloseError
if !errors.As(err, &cerr) { if !errors.As(err, &cerr) {
...@@ -1898,24 +1858,6 @@ func assertCloseStatus(err error, code websocket.StatusCode) error { ...@@ -1898,24 +1858,6 @@ func assertCloseStatus(err error, code websocket.StatusCode) error {
return assertEqualf(code, cerr.Code, "unexpected status code") return assertEqualf(code, cerr.Code, "unexpected status code")
} }
func assertJSONRead(ctx context.Context, c *websocket.Conn, exp interface{}) (err error) {
var act interface{}
err = wsjson.Read(ctx, c, &act)
if err != nil {
return err
}
return assertEqualf(exp, act, "unexpected JSON")
}
func randBytes(n int) []byte {
return make([]byte, n)
}
func randString(n int) string {
return string(randBytes(n))
}
func assertEcho(ctx context.Context, c *websocket.Conn, typ websocket.MessageType, n int) error { func assertEcho(ctx context.Context, c *websocket.Conn, typ websocket.MessageType, n int) error {
p := randBytes(n) p := randBytes(n)
err := c.Write(ctx, typ, p) err := c.Write(ctx, typ, p)
...@@ -1949,13 +1891,6 @@ func assertSubprotocol(c *websocket.Conn, exp string) error { ...@@ -1949,13 +1891,6 @@ func assertSubprotocol(c *websocket.Conn, exp string) error {
return assertEqualf(exp, c.Subprotocol(), "unexpected subprotocol") return assertEqualf(exp, c.Subprotocol(), "unexpected subprotocol")
} }
func assertEqualf(exp, act interface{}, f string, v ...interface{}) error {
if diff := cmpDiff(exp, act); diff != "" {
return fmt.Errorf(f+": %v", append(v, diff)...)
}
return nil
}
func assertNetConnRead(r io.Reader, exp string) error { func assertNetConnRead(r io.Reader, exp string) error {
act := make([]byte, len(exp)) act := make([]byte, len(exp))
_, err := r.Read(act) _, err := r.Read(act)
......
...@@ -54,5 +54,5 @@ func write(ctx context.Context, c *websocket.Conn, v interface{}) error { ...@@ -54,5 +54,5 @@ func write(ctx context.Context, c *websocket.Conn, v interface{}) error {
return err return err
} }
return c.Write(ctx, websocket.MessageBinary, b) return c.Write(ctx, websocket.MessageText, b)
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment