From 76a6a2631ff5efecc76b904553e692886b0e0b76 Mon Sep 17 00:00:00 2001 From: Anmol Sethi <hi@nhooyr.io> Date: Sun, 22 Sep 2019 12:21:46 -0500 Subject: [PATCH] Improve wasm test coverage --- assert_test.go | 29 ++++++++++++++++++-- ci/wasm.sh | 19 +++++++------ go.mod | 1 - internal/wsecho/cmd/wsecho/main.go | 21 --------------- internal/wsecho/wsecho.go | 22 ++------------- internal/wsjs/wsjs.go | 2 +- internal/wsjstest/main.go | 43 ++++++++++++++++++++++++++++++ netconn_js.go | 17 ------------ netconn_normal.go | 12 --------- websocket.go | 4 +++ websocket_js.go | 22 ++++++++++----- websocket_js_test.go | 20 +++++++++++--- websocket_test.go | 21 --------------- 13 files changed, 120 insertions(+), 113 deletions(-) delete mode 100644 internal/wsecho/cmd/wsecho/main.go create mode 100644 internal/wsjstest/main.go delete mode 100644 netconn_js.go delete mode 100644 netconn_normal.go diff --git a/assert_test.go b/assert_test.go index 2f05337..cddae99 100644 --- a/assert_test.go +++ b/assert_test.go @@ -2,7 +2,9 @@ package websocket_test import ( "context" + "encoding/hex" "fmt" + "math/rand" "reflect" "github.com/google/go-cmp/cmp" @@ -91,9 +93,32 @@ func assertJSONRead(ctx context.Context, c *websocket.Conn, exp interface{}) err } func randBytes(n int) []byte { - return make([]byte, n) + b := make([]byte, n) + rand.Read(b) + return b } func randString(n int) string { - return string(randBytes(n)) + return hex.EncodeToString(randBytes(n))[:n] +} + +func assertEcho(ctx context.Context, c *websocket.Conn, typ websocket.MessageType, n int) error { + p := randBytes(n) + err := c.Write(ctx, typ, p) + if err != nil { + return err + } + typ2, p2, err := c.Read(ctx) + if err != nil { + return err + } + err = assertEqualf(typ, typ2, "unexpected data type") + if err != nil { + return err + } + return assertEqualf(p, p2, "unexpected payload") +} + +func assertSubprotocol(c *websocket.Conn, exp string) error { + return assertEqualf(exp, c.Subprotocol(), "unexpected subprotocol") } diff --git a/ci/wasm.sh b/ci/wasm.sh index eb4a0cf..0290f18 100755 --- a/ci/wasm.sh +++ b/ci/wasm.sh @@ -9,19 +9,22 @@ GOOS=js GOARCH=wasm go vet ./... go install golang.org/x/lint/golint GOOS=js GOARCH=wasm golint -set_exit_status ./... -wsEchoOut="$(mktemp -d)/stdout" -mkfifo "$wsEchoOut" -go install ./internal/wsecho/cmd/wsecho -wsecho > "$wsEchoOut" & +wsjstestOut="$(mktemp -d)/stdout" +mkfifo "$wsjstestOut" +go install ./internal/wsjstest +timeout 30s wsjstest > "$wsjstestOut" & +wsjstestPID=$! -WS_ECHO_SERVER_URL="$(timeout 10s head -n 1 "$wsEchoOut")" || true +WS_ECHO_SERVER_URL="$(timeout 10s head -n 1 "$wsjstestOut")" || true if [[ -z $WS_ECHO_SERVER_URL ]]; then - echo "./internal/wsecho/cmd/wsecho failed to start in 10s" + echo "./internal/wsjstest failed to start in 10s" exit 1 fi go install github.com/agnivade/wasmbrowsertest GOOS=js GOARCH=wasm go test -exec=wasmbrowsertest ./... -args "$WS_ECHO_SERVER_URL" -kill %1 -wait -n || true +if ! wait "$wsjstestPID"; then + echo "wsjstest exited unsuccessfully" + exit 1 +fi diff --git a/go.mod b/go.mod index ab46375..86a9403 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,6 @@ require ( golang.org/x/sys v0.0.0-20190919044723-0c1ff786ef13 // indirect golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72 - golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gotest.tools/gotestsum v0.3.5 mvdan.cc/sh v2.6.4+incompatible diff --git a/internal/wsecho/cmd/wsecho/main.go b/internal/wsecho/cmd/wsecho/main.go deleted file mode 100644 index 9d9dc82..0000000 --- a/internal/wsecho/cmd/wsecho/main.go +++ /dev/null @@ -1,21 +0,0 @@ -// +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() -} diff --git a/internal/wsecho/wsecho.go b/internal/wsecho/wsecho.go index 8f531f1..c408f07 100644 --- a/internal/wsecho/wsecho.go +++ b/internal/wsecho/wsecho.go @@ -5,33 +5,15 @@ 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 << 30. -func Loop(ctx context.Context, c *websocket.Conn) { +func Loop(ctx context.Context, c *websocket.Conn) error { defer c.Close(websocket.StatusInternalError, "") c.SetReadLimit(1 << 30) @@ -67,7 +49,7 @@ func Loop(ctx context.Context, c *websocket.Conn) { for { err := echo() if err != nil { - return + return err } } } diff --git a/internal/wsjs/wsjs.go b/internal/wsjs/wsjs.go index f83b766..68078cf 100644 --- a/internal/wsjs/wsjs.go +++ b/internal/wsjs/wsjs.go @@ -41,7 +41,7 @@ func New(url string, protocols []string) (c WebSocket, err error) { v: js.Global().Get("WebSocket").New(url, jsProtocols), } - c.setBinaryType("arrayBuffer") + c.setBinaryType("arraybuffer") c.Extensions = c.v.Get("extensions").String() c.Protocol = c.v.Get("protocol").String() diff --git a/internal/wsjstest/main.go b/internal/wsjstest/main.go new file mode 100644 index 0000000..a1ad1b0 --- /dev/null +++ b/internal/wsjstest/main.go @@ -0,0 +1,43 @@ +// +build !js + +package main + +import ( + "errors" + "fmt" + "log" + "net/http" + "net/http/httptest" + "os" + "runtime" + "strings" + + "nhooyr.io/websocket" + "nhooyr.io/websocket/internal/wsecho" +) + +func main() { + s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + c, err := websocket.Accept(w, r, &websocket.AcceptOptions{ + Subprotocols: []string{"echo"}, + InsecureSkipVerify: true, + }) + if err != nil { + log.Fatalf("echo server: failed to accept: %+v", err) + } + defer c.Close(websocket.StatusInternalError, "") + + err = wsecho.Loop(r.Context(), c) + + var ce websocket.CloseError + if !errors.As(err, &ce) || ce.Code != websocket.StatusNormalClosure { + log.Fatalf("unexpected loop error: %+v", err) + } + + os.Exit(0) + })) + wsURL := strings.Replace(s.URL, "http", "ws", 1) + fmt.Printf("%v\n", wsURL) + + runtime.Goexit() +} diff --git a/netconn_js.go b/netconn_js.go deleted file mode 100644 index 5cd15d4..0000000 --- a/netconn_js.go +++ /dev/null @@ -1,17 +0,0 @@ -// +build js - -package websocket - -import ( - "bytes" - "context" - "io" -) - -func (c *netConn) netConnReader(ctx context.Context) (MessageType, io.Reader, error) { - typ, p, err := c.c.Read(ctx) - if err != nil { - return 0, nil, err - } - return typ, bytes.NewReader(p), nil -} diff --git a/netconn_normal.go b/netconn_normal.go deleted file mode 100644 index 0db551d..0000000 --- a/netconn_normal.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build !js - -package websocket - -import ( - "context" - "io" -) - -func (c *netConn) netConnReader(ctx context.Context) (MessageType, io.Reader, error) { - return c.c.Reader(c.readContext) -} diff --git a/websocket.go b/websocket.go index 596d89f..bbadb9b 100644 --- a/websocket.go +++ b/websocket.go @@ -946,3 +946,7 @@ func (c *Conn) extractBufioWriterBuf(w io.Writer) { c.bw.Reset(w) } + +func (c *netConn) netConnReader(ctx context.Context) (MessageType, io.Reader, error) { + return c.c.Reader(c.readContext) +} diff --git a/websocket_js.go b/websocket_js.go index 0782e04..14f198d 100644 --- a/websocket_js.go +++ b/websocket_js.go @@ -1,17 +1,17 @@ package websocket // import "nhooyr.io/websocket" import ( + "bytes" "context" "errors" "fmt" + "io" "net/http" "reflect" "runtime" "sync" "syscall/js" - "golang.org/x/xerrors" - "nhooyr.io/websocket/internal/wsjs" ) @@ -35,9 +35,6 @@ func (c *Conn) close(err error) { c.closeErr = fmt.Errorf("websocket closed: %w", err) close(c.closed) - - c.releaseOnClose() - c.releaseOnMessage() }) } @@ -52,6 +49,9 @@ func (c *Conn) init() { } c.close(fmt.Errorf("received close frame: %w", cerr)) + + c.releaseOnClose() + c.releaseOnMessage() }) c.releaseOnMessage = c.ws.OnMessage(func(e wsjs.MessageEvent) { @@ -144,8 +144,8 @@ func (c *Conn) Close(code StatusCode, reason string) error { } c.close(err) - if !xerrors.Is(c.closeErr, err) { - return xerrors.Errorf("failed to close websocket: %w", err) + if !errors.Is(c.closeErr, err) { + return fmt.Errorf("failed to close websocket: %w", err) } return nil @@ -207,3 +207,11 @@ func dial(ctx context.Context, url string, opts *DialOptions) (*Conn, *http.Resp // Have to return a non nil response as the normal API does that. return c, &http.Response{}, nil } + +func (c *netConn) netConnReader(ctx context.Context) (MessageType, io.Reader, error) { + typ, p, err := c.c.Read(ctx) + if err != nil { + return 0, nil, err + } + return typ, bytes.NewReader(p), nil +} diff --git a/websocket_js_test.go b/websocket_js_test.go index 9ced658..1142190 100644 --- a/websocket_js_test.go +++ b/websocket_js_test.go @@ -10,7 +10,7 @@ import ( "nhooyr.io/websocket" ) -func TestWebSocket(t *testing.T) { +func TestConn(t *testing.T) { t.Parallel() wsEchoServerURL := flag.Arg(0) @@ -18,18 +18,30 @@ func TestWebSocket(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() - c, resp, err := websocket.Dial(ctx, wsEchoServerURL, nil) + c, resp, err := websocket.Dial(ctx, wsEchoServerURL, &websocket.DialOptions{ + Subprotocols: []string{"echo"}, + }) if err != nil { t.Fatal(err) } defer c.Close(websocket.StatusInternalError, "") + assertSubprotocol(c, "echo") + if err != nil { + t.Fatal(err) + } + err = assertEqualf(&http.Response{}, resp, "unexpected http response") if err != nil { t.Fatal(err) } - err = assertJSONEcho(ctx, c, 4096) + err = assertJSONEcho(ctx, c, 16) + if err != nil { + t.Fatal(err) + } + + err = assertEcho(ctx, c, websocket.MessageBinary, 16) if err != nil { t.Fatal(err) } @@ -38,4 +50,6 @@ func TestWebSocket(t *testing.T) { if err != nil { t.Fatal(err) } + + time.Sleep(time.Millisecond * 100) } diff --git a/websocket_test.go b/websocket_test.go index 36a5224..2fabba5 100644 --- a/websocket_test.go +++ b/websocket_test.go @@ -1858,23 +1858,6 @@ func assertCloseStatus(err error, code websocket.StatusCode) error { return assertEqualf(code, cerr.Code, "unexpected status code") } -func assertEcho(ctx context.Context, c *websocket.Conn, typ websocket.MessageType, n int) error { - p := randBytes(n) - err := c.Write(ctx, typ, p) - if err != nil { - return err - } - typ2, p2, err := c.Read(ctx) - if err != nil { - return err - } - err = assertEqualf(typ, typ2, "unexpected data type") - if err != nil { - return err - } - return assertEqualf(p, p2, "unexpected payload") -} - func assertProtobufRead(ctx context.Context, c *websocket.Conn, exp interface{}) error { expType := reflect.TypeOf(exp) actv := reflect.New(expType.Elem()) @@ -1887,10 +1870,6 @@ func assertProtobufRead(ctx context.Context, c *websocket.Conn, exp interface{}) return assertEqualf(exp, act, "unexpected protobuf") } -func assertSubprotocol(c *websocket.Conn, exp string) error { - return assertEqualf(exp, c.Subprotocol(), "unexpected subprotocol") -} - func assertNetConnRead(r io.Reader, exp string) error { act := make([]byte, len(exp)) _, err := r.Read(act) -- GitLab