wsmock

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 22, 2026 License: MIT Imports: 12 Imported by: 0

README

wsmock

Go Reference Go Report Card

wsmock is an expressive, zero-boilerplate WebSocket mock server for Go testing. It provides a declarative scenario builder and fault injection engine (network drops, slow responses, abnormal closure codes) to make testing WebSocket clients and services effortless.


Features

  • Zero Setup: Start an in-memory WebSocket mock server with one line (wsmock.NewServer(t)).
  • Declarative Expectations: Mock request-response patterns with ExpectMessage, ExpectJSON, or ExpectBinary.
  • Chaos and Fault Injection:
    • DropConnection(): Abruptly drops the underlying TCP socket without an RFC close frame (ideal for testing auto-reconnect logic).
    • CloseWithCode(code, reason): Sends RFC 6455 close frames (e.g., 1008 Policy Violation, 1011 Server Error).
    • Delay(d): Simulates network latency and slow responses.
  • Broadcast and Streaming: Push unprompted events to connected clients.
  • Recorded History and Assertions: Inspect and assert received payloads and expectation fulfillment.
  • Thread-Safe: Fully safe for concurrent test execution and tested with -race.

Installation

go get github.com/sing198/wsmock

Quick Start

1. Basic Request & Reply
func TestClientEcho(t *testing.T) {
    srv := wsmock.NewServer(t)

    // Set up expectation
    srv.ExpectMessage("ping").Reply("pong")

    // Connect client to srv.URL()
    conn, _, err := websocket.DefaultDialer.Dial(srv.URL(), nil)
    require.NoError(t, err)
    defer conn.Close()

    // Send and verify
    _ = conn.WriteMessage(websocket.TextMessage, []byte("ping"))
    _, reply, _ := conn.ReadMessage()
    assert.Equal(t, "pong", string(reply))

    // Assert that the expected message was received
    srv.AssertExpectationsMet()
}
2. Testing JSON Payloads
type AuthRequest struct {
    Token string `json:"token"`
}

type AuthResponse struct {
    Success bool `json:"success"`
}

func TestClientAuth(t *testing.T) {
    srv := wsmock.NewServer(t)

    srv.ExpectJSON(AuthRequest{Token: "secret"}).
        ReplyJSON(AuthResponse{Success: true})

    // ... dial and test your client ...
}
3. Fault Injection: Testing Reconnection Logic

Simulate abrupt network cuts without an RFC close frame to ensure reconnection clients recover gracefully:

func TestClientReconnectOnNetworkLoss(t *testing.T) {
    srv := wsmock.NewServer(t)

    // Abruptly sever the TCP connection upon receiving "trigger-drop"
    srv.ExpectMessage("trigger-drop").DropConnection()

    // Or close with specific close code:
    // srv.ExpectMessage("forbidden").CloseWithCode(websocket.ClosePolicyViolation, "denied")

    // Run client under test...
}
4. Broadcasting & Server Pushes
func TestServerStreaming(t *testing.T) {
    srv := wsmock.NewServer(t)

    // Broadcast messages to all active connections
    srv.Broadcast("ticker-update:100.5")

    // Or broadcast structured JSON
    srv.BroadcastJSON(MyEvent{Type: "price", Value: 100.5})
}

License

MIT © Thanaphat Khunphet

Documentation

Overview

Package wsmock provides an in-memory WebSocket mock server for Go testing. It simplifies testing WebSocket clients by providing declarative request-response expectations, chaos fault injection (abrupt socket drops, custom close frames, delays), connection lifecycle hooks, and message assertions.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Action

type Action func(conn *Conn, messageType int, payload []byte) error

Action defines an action executed when an expectation matches.

type Conn

type Conn struct {
	// contains filtered or unexported fields
}

Conn represents an active client connection to the mock server.

func (*Conn) Close

func (c *Conn) Close() error

Close cleanly closes the WebSocket connection with CloseNormalClosure (1000).

func (*Conn) CloseWithCode

func (c *Conn) CloseWithCode(code int, reason string) error

CloseWithCode cleanly closes the WebSocket connection with a specific RFC 6455 code and reason.

func (*Conn) DropConnection

func (c *Conn) DropConnection() error

DropConnection abruptly closes the underlying TCP connection without sending a WebSocket close frame, simulating unexpected network loss or process crash.

func (*Conn) SendBinary

func (c *Conn) SendBinary(data []byte) error

SendBinary sends binary payload to this connection.

func (*Conn) SendJSON

func (c *Conn) SendJSON(v any) error

SendJSON marshals v and sends it as a text message to this connection.

func (*Conn) SendMessage

func (c *Conn) SendMessage(msg string) error

SendMessage sends a text message to this connection.

type Expectation

type Expectation struct {
	// contains filtered or unexported fields
}

Expectation represents a mocked client-server interaction rule.

func (*Expectation) AnyTimes

func (e *Expectation) AnyTimes() *Expectation

AnyTimes removes any invocation limit on this expectation.

func (*Expectation) CloseWithCode

func (e *Expectation) CloseWithCode(code int, reason string) *Expectation

CloseWithCode cleanly closes the connection with code & reason upon match.

func (*Expectation) Delay

func (e *Expectation) Delay(d time.Duration) *Expectation

Delay introduces an artificial response latency before subsequent actions.

func (*Expectation) DropConnection

func (e *Expectation) DropConnection() *Expectation

DropConnection drops the connection when this expectation matches.

func (*Expectation) Once

func (e *Expectation) Once() *Expectation

Once is a shorthand for Times(1).

func (*Expectation) Reply

func (e *Expectation) Reply(msg string) *Expectation

Reply queues a text response back to the client.

func (*Expectation) ReplyBinary

func (e *Expectation) ReplyBinary(data []byte) *Expectation

ReplyBinary queues binary bytes back to the client.

func (*Expectation) ReplyJSON

func (e *Expectation) ReplyJSON(v any) *Expectation

ReplyJSON serializes v as JSON and queues it back to the client.

func (*Expectation) Times

func (e *Expectation) Times(n int) *Expectation

Times sets the number of times this expectation is allowed to match.

type Matcher

type Matcher func(messageType int, payload []byte) bool

Matcher determines if an incoming message matches the expectation.

type Option

type Option func(*Server)

Option allows configuring Server properties.

func WithCheckOrigin

func WithCheckOrigin(check func(r *http.Request) bool) Option

WithCheckOrigin sets a custom origin verification function.

type ReceivedMessage

type ReceivedMessage struct {
	Type      int
	Payload   []byte
	Timestamp time.Time
}

ReceivedMessage represents an incoming message recorded by the mock server.

func (ReceivedMessage) JSON

func (m ReceivedMessage) JSON(target any) error

JSON unmarshals the payload into the given target pointer.

func (ReceivedMessage) Text

func (m ReceivedMessage) Text() string

Text returns the payload as a string.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is the in-memory mock WebSocket server.

func NewServer

func NewServer(t testing.TB, opts ...Option) *Server

NewServer creates and immediately starts a new mock WebSocket server.

func (*Server) AssertExpectationsMet

func (s *Server) AssertExpectationsMet()

AssertExpectationsMet verifies that all registered expectations were satisfied.

func (*Server) AssertReceived

func (s *Server) AssertReceived(expected string)

AssertReceived fails the test if no message matching expected was received.

func (*Server) AssertReceivedCount

func (s *Server) AssertReceivedCount(expectedCount int)

AssertReceivedCount fails the test if total received messages != expectedCount.

func (*Server) AssertReceivedJSON

func (s *Server) AssertReceivedJSON(expected any)

AssertReceivedJSON fails the test if no message matching expected JSON was received.

func (*Server) Broadcast

func (s *Server) Broadcast(msg string)

Broadcast sends a text message to all currently connected clients.

func (*Server) BroadcastJSON

func (s *Server) BroadcastJSON(v any) error

BroadcastJSON serializes v and sends it to all currently connected clients.

func (*Server) ClientCount

func (s *Server) ClientCount() int

ClientCount returns the number of currently active connections.

func (*Server) Close

func (s *Server) Close()

Close terminates the mock server and cleans up all active connections.

func (*Server) Connections

func (s *Server) Connections() []*Conn

Connections returns a snapshot of currently active connections.

func (*Server) ExpectBinary

func (s *Server) ExpectBinary(data []byte) *Expectation

ExpectBinary registers an expectation matching exact binary payloads.

func (*Server) ExpectCustom

func (s *Server) ExpectCustom(matcher Matcher, desc string) *Expectation

ExpectCustom registers an expectation with custom matcher logic.

func (*Server) ExpectJSON

func (s *Server) ExpectJSON(v any) *Expectation

ExpectJSON registers an expectation matching incoming JSON messages.

func (*Server) ExpectMessage

func (s *Server) ExpectMessage(msg string) *Expectation

ExpectMessage registers an expectation matching incoming text messages exactly.

func (*Server) OnConnect

func (s *Server) OnConnect(fn func(*Conn)) *Server

OnConnect registers a callback invoked whenever a new WebSocket connection is established.

func (*Server) OnDisconnect

func (s *Server) OnDisconnect(fn func(*Conn)) *Server

OnDisconnect registers a callback invoked whenever a WebSocket connection closes.

func (*Server) ReceivedMessages

func (s *Server) ReceivedMessages() []ReceivedMessage

ReceivedMessages returns all recorded messages received by the server.

func (*Server) URL

func (s *Server) URL() string

URL returns the ws:// endpoint of the mock server.

func (*Server) WaitMessages

func (s *Server) WaitMessages(count int, timeout time.Duration) error

WaitMessages waits until at least n messages have arrived or timeout is reached.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL