Skip to content

Commit de687ea

Browse files
committed
More test coverage and updated CONTRIBUTING.md
1 parent 537b26b commit de687ea

File tree

4 files changed

+171
-14
lines changed

4 files changed

+171
-14
lines changed

ci/image/Dockerfile

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ ENV GOFLAGS="-mod=readonly"
66
ENV PAGER=cat
77

88
RUN apt-get update && \
9-
apt-get install -y shellcheck python-pip npm && \
10-
pip2 install autobahntestsuite && \
9+
apt-get install -y shellcheck npm && \
1110
npm install -g prettier
1211

13-
RUN git config --global color.ui always
12+
RUN git config --global color.ui always

docs/CONTRIBUTING.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,21 @@ browse coverage.
3434

3535
You can run CI locally. The various steps are located in `ci/*.sh`.
3636

37-
1. `ci/fmt.sh` requires node (specifically prettier).
38-
1. `ci/lint.sh` requires [shellcheck](https://github.com/koalaman/shellcheck#installing).
39-
1. `ci/test.sh` requires the [Autobahn Test suite pip package](https://github.com/crossbario/autobahn-testsuite).
40-
1. `ci/run.sh` runs the above scripts in order.
37+
1. `ci/fmt.sh` which requires node (specifically prettier).
38+
1. `ci/lint.sh` which requires [shellcheck](https://github.com/koalaman/shellcheck#installing).
39+
1. `ci/test.sh`
40+
1. `ci/run.sh` which runs the above scripts in order.
4141

4242
For coverage details locally, please see `ci/out/coverage.html` after running `ci/test.sh`.
4343

4444
See [ci/image/Dockerfile](ci/image/Dockerfile) for the installation of the CI dependencies on Ubuntu.
4545

46-
You can also run tests normally with `go test` once you have the
47-
[Autobahn Test suite pip package](https://github.com/crossbario/autobahn-testsuite)
48-
installed. `ci/test.sh` just passes a default set of flags to `go test` to collect coverage,
46+
You can also run tests normally with `go test`.
47+
`ci/test.sh` just passes a default set of flags to `go test` to collect coverage,
4948
enable the race detector, run benchmarks and also prettifies the output.
49+
50+
If you pass flags to `ci/test.sh`, it will pass those flags directly to `go test` but will also
51+
collect coverage for you. This is nice for when you don't want to wait for benchmarks
52+
or the race detector but want to have coverage.
53+
54+
Coverage percentage from codecov and the CI scripts will be different because they are calculated differently.

export_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ type Addr = websocketAddr
88

99
type Header = header
1010

11+
const OPClose = opClose
12+
const OPPing = opPing
13+
1114
func (c *Conn) WriteFrame(ctx context.Context, fin bool, opcode opcode, p []byte) (int, error) {
1215
return c.writeFrame(ctx, fin, opcode, p)
1316
}
17+
18+
func (c *Conn) Flush() error {
19+
return c.bw.Flush()
20+
}

websocket_test.go

Lines changed: 150 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7-
"github.com/golang/protobuf/proto"
8-
"github.com/golang/protobuf/ptypes/timestamp"
97
"io"
108
"io/ioutil"
119
"math/rand"
@@ -23,8 +21,10 @@ import (
2321
"testing"
2422
"time"
2523

24+
"github.com/golang/protobuf/proto"
2625
"github.com/golang/protobuf/ptypes"
2726
"github.com/golang/protobuf/ptypes/duration"
27+
"github.com/golang/protobuf/ptypes/timestamp"
2828
"github.com/google/go-cmp/cmp"
2929
"golang.org/x/xerrors"
3030

@@ -592,7 +592,7 @@ func TestConn(t *testing.T) {
592592
return nil
593593
},
594594
client: func(ctx context.Context, c *websocket.Conn) error {
595-
go c.CloseRead(ctx)
595+
c.CloseRead(ctx)
596596

597597
err := c.Write(ctx, websocket.MessageBinary, []byte(strings.Repeat("x", 32769)))
598598
if err != nil {
@@ -775,7 +775,7 @@ func TestConn(t *testing.T) {
775775
}
776776
<-ctx.Done()
777777
_, err = r.Read(make([]byte, 1))
778-
if !xerrors.Is(err, context.DeadlineExceeded){
778+
if !xerrors.Is(err, context.DeadlineExceeded) {
779779
return xerrors.Errorf("expected deadline exceeded error: %+v", err)
780780
}
781781
return nil
@@ -829,6 +829,152 @@ func TestConn(t *testing.T) {
829829
return nil
830830
},
831831
},
832+
{
833+
name: "largeControlFrame",
834+
server: func(ctx context.Context, c *websocket.Conn) error {
835+
_, err := c.WriteFrame(ctx, true, websocket.OPClose, []byte(strings.Repeat("x", 4096)))
836+
if err != nil {
837+
return err
838+
}
839+
_, _, err = c.Read(ctx)
840+
cerr := &websocket.CloseError{}
841+
if !xerrors.As(err, cerr) || cerr.Code != websocket.StatusProtocolError {
842+
return xerrors.Errorf("expected close error with StatusProtocolError: %+v", err)
843+
}
844+
return nil
845+
},
846+
client: func(ctx context.Context, c *websocket.Conn) error {
847+
_, _, err := c.Read(ctx)
848+
if err == nil || !strings.Contains(err.Error(), "too large") {
849+
return xerrors.Errorf("expected error that contains too large: %+v", err)
850+
}
851+
return nil
852+
},
853+
},
854+
{
855+
name: "fragmentedControlFrame",
856+
server: func(ctx context.Context, c *websocket.Conn) error {
857+
_, err := c.WriteFrame(ctx, false, websocket.OPPing, []byte(strings.Repeat("x", 32)))
858+
if err != nil {
859+
return err
860+
}
861+
err = c.Flush()
862+
if err != nil {
863+
return err
864+
}
865+
_, _, err = c.Read(ctx)
866+
cerr := &websocket.CloseError{}
867+
if !xerrors.As(err, cerr) || cerr.Code != websocket.StatusProtocolError {
868+
return xerrors.Errorf("expected close error with StatusProtocolError: %+v", err)
869+
}
870+
return nil
871+
},
872+
client: func(ctx context.Context, c *websocket.Conn) error {
873+
_, _, err := c.Read(ctx)
874+
if err == nil || !strings.Contains(err.Error(), "fragmented") {
875+
return xerrors.Errorf("expected error that contains fragmented: %+v", err)
876+
}
877+
return nil
878+
},
879+
},
880+
{
881+
name: "invalidClosePayload",
882+
server: func(ctx context.Context, c *websocket.Conn) error {
883+
_, err := c.WriteFrame(ctx, true, websocket.OPClose, []byte{0x17, 0x70})
884+
if err != nil {
885+
return err
886+
}
887+
_, _, err = c.Read(ctx)
888+
cerr := &websocket.CloseError{}
889+
if !xerrors.As(err, cerr) || cerr.Code != websocket.StatusProtocolError {
890+
return xerrors.Errorf("expected close error with StatusProtocolError: %+v", err)
891+
}
892+
return nil
893+
},
894+
client: func(ctx context.Context, c *websocket.Conn) error {
895+
_, _, err := c.Read(ctx)
896+
if err == nil || !strings.Contains(err.Error(), "invalid status code") {
897+
return xerrors.Errorf("expected error that contains invalid status code: %+v", err)
898+
}
899+
return nil
900+
},
901+
},
902+
{
903+
name: "doubleReader",
904+
server: func(ctx context.Context, c *websocket.Conn) error {
905+
_, r, err := c.Reader(ctx)
906+
if err != nil {
907+
return err
908+
}
909+
p := make([]byte, 10)
910+
_, err = io.ReadFull(r, p)
911+
if err != nil {
912+
return err
913+
}
914+
_, _, err = c.Reader(ctx)
915+
if err == nil {
916+
return xerrors.Errorf("expected non nil error: %v", err)
917+
}
918+
return nil
919+
},
920+
client: func(ctx context.Context, c *websocket.Conn) error {
921+
err := c.Write(ctx, websocket.MessageBinary, []byte(strings.Repeat("x", 11)))
922+
if err != nil {
923+
return err
924+
}
925+
_, _, err = c.Read(ctx)
926+
if err == nil {
927+
return xerrors.Errorf("expected non nil error: %v", err)
928+
}
929+
return nil
930+
},
931+
},
932+
{
933+
name: "doubleFragmentedReader",
934+
server: func(ctx context.Context, c *websocket.Conn) error {
935+
_, r, err := c.Reader(ctx)
936+
if err != nil {
937+
return err
938+
}
939+
p := make([]byte, 10)
940+
_, err = io.ReadFull(r, p)
941+
if err != nil {
942+
return err
943+
}
944+
_, _, err = c.Reader(ctx)
945+
if err == nil {
946+
return xerrors.Errorf("expected non nil error: %v", err)
947+
}
948+
return nil
949+
},
950+
client: func(ctx context.Context, c *websocket.Conn) error {
951+
w, err := c.Writer(ctx, websocket.MessageBinary)
952+
if err != nil {
953+
return err
954+
}
955+
_, err = w.Write([]byte(strings.Repeat("x", 10)))
956+
if err != nil {
957+
return xerrors.Errorf("expected non nil error")
958+
}
959+
err = c.Flush()
960+
if err != nil {
961+
return xerrors.Errorf("failed to flush: %w", err)
962+
}
963+
_, err = w.Write([]byte(strings.Repeat("x", 10)))
964+
if err != nil {
965+
return xerrors.Errorf("expected non nil error")
966+
}
967+
err = c.Flush()
968+
if err != nil {
969+
return xerrors.Errorf("failed to flush: %w", err)
970+
}
971+
_, _, err = c.Read(ctx)
972+
if err == nil {
973+
return xerrors.Errorf("expected non nil error: %v", err)
974+
}
975+
return nil
976+
},
977+
},
832978
}
833979
for _, tc := range testCases {
834980
tc := tc

0 commit comments

Comments
 (0)