Documentation
¶
Overview ¶
Package jawstest provides an importable harness for driving a jaws.Request's WebSocket message-processing loop in tests.
It lives in its own package, rather than in package jaws, so that net/http/httptest stays out of the production build of consumers that import github.com/linkdata/jaws. It reaches the request loop through the exported jaws.Jaws.TestServe hook.
Harness channels are intentionally low-level. Tests that drive output must drain TestRequest.OutCh, and after TestRequest.Close should wait for TestRequest.DoneCh before returning. Close is a single-use operation because it closes the inbound channel directly.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type TestRequest ¶
type TestRequest struct {
*jaws.Request
Recorder *httptest.ResponseRecorder // sink for the test's own rendering; the harness never writes to it
ReadyCh chan struct{} // closed once the processing loop is running
DoneCh chan struct{} // closed once the processing loop has stopped
InCh chan wire.WsMsg // send inbound WebSocket messages here
OutCh chan wire.WsMsg // outbound messages; buffered but must be drained or the loop stalls
BcastCh chan wire.Message // inject broadcasts here
}
TestRequest is a request harness intended for tests.
The embedded jaws.Request provides the usual request methods (NewElement, JawsKeyString, and so on). The channels expose the loop's wiring: send incoming WebSocket messages on InCh, read outbound messages from OutCh, and inject broadcasts on BcastCh. ReadyCh is closed once the loop is running and DoneCh once it has stopped.
OutCh is buffered but must be drained: a test that produces more outbound messages than the buffer holds without reading OutCh stalls the loop, and a wait on DoneCh after TestRequest.Close then never completes.
Recorder is a sink for the test's own rendering, for example as the Writer of a ui.RequestWriter; nothing in the harness writes to it.
func NewTestRequest ¶
func NewTestRequest(jw *jaws.Jaws, r *http.Request) *TestRequest
NewTestRequest creates and serves a TestRequest for jw.
Passing nil for r uses a GET / request with no body.
It requires the Jaws processing loop (jaws.Jaws.Serve or jaws.Jaws.ServeWithTimeout) to be running, and returns nil if the request cannot be created or claimed.
Example ¶
package main
import (
"fmt"
"github.com/linkdata/jaws"
"github.com/linkdata/jaws/jawstest"
)
func main() {
jw, err := jaws.New()
if err != nil {
panic(err)
}
defer jw.Close()
go jw.Serve()
tr := jawstest.NewTestRequest(jw, nil)
if tr == nil {
panic("request was not created")
}
<-tr.ReadyCh
drained := make(chan struct{})
go func() {
defer close(drained)
for {
select {
case <-tr.OutCh:
case <-tr.DoneCh:
return
}
}
}()
tr.Close()
<-tr.DoneCh
<-drained
fmt.Println("stopped")
}
Output: stopped
func (*TestRequest) BodyHTML ¶
func (tr *TestRequest) BodyHTML() template.HTML
BodyHTML returns the recorded response body as trusted html/template.HTML.
The body is whatever the test itself rendered into TestRequest.Recorder, so it is treated as trusted; do not feed untrusted input through Recorder when the result is rendered as HTML.
func (*TestRequest) BodyString ¶
func (tr *TestRequest) BodyString() string
BodyString returns the recorded response body with surrounding whitespace removed.
func (*TestRequest) Close ¶
func (tr *TestRequest) Close()
Close stops the test request's processing loop by closing InCh.
It does not wait for the loop to stop; wait on DoneCh for that. Calling Close more than once panics.