Documentation ¶
Overview ¶
Package spawntest helps write tests that use subprocesses.
The subprocess runs a HTTP server on a UNIX domain socket, and the test can make HTTP requests to control the behavior of the helper subprocess.
Helpers are identified by names they pass to Registry.Register. This call should be placed in an init function. The test spawns the subprocess by executing the same test binary in a subprocess, passing it a special flag that is recognized by TestMain.
This might get extracted to a standalone repository, if it proves useful enough.
Example ¶
package main import ( "context" "errors" "flag" "os" "testing" "github.com/chemistry-sourabh/fuse/fs/fstestutil/spawntest" "github.com/chemistry-sourabh/fuse/fs/fstestutil/spawntest/httpjson" ) var helpers spawntest.Registry type addRequest struct { A uint64 B uint64 } type addResult struct { X uint64 } func add(ctx context.Context, req addRequest) (*addResult, error) { // In real tests, you'd instruct the helper to interact with the // system-under-test on behalf of the unit test process. For // brevity, we'll just do the action directly in this example. x := req.A + req.B if x < req.A { return nil, errors.New("overflow") } r := &addResult{ X: x, } return r, nil } // The second argument to Register can be any http.Handler. To keep // state in the helper between calls, you can create a custom type and // delegate to methods based on http.Request.URL.Path. var addHelper = helpers.Register("add", httpjson.ServePOST(add)) func name_me_TestAdd(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() control := addHelper.Spawn(ctx, t) defer control.Close() var got addResult if err := control.JSON("/").Call(ctx, addRequest{A: 42, B: 13}, &got); err != nil { t.Fatalf("calling helper: %v", err) } if g, e := got.X, uint64(55); g != e { t.Errorf("wrong add result: %v != %v", g, e) } } func name_me_TestMain(m *testing.M) { helpers.AddFlag(flag.CommandLine) flag.Parse() helpers.RunIfNeeded() os.Exit(m.Run()) } func main() {} // Quiet linters. See https://github.com/dominikh/go-tools/issues/675 var _ = name_me_TestAdd var _ = name_me_TestMain
Output:
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Control ¶
type Control struct {
// contains filtered or unexported fields
}
Control an instance of a helper running as a subprocess.
func (*Control) HTTP ¶
HTTP returns a HTTP client that can be used to communicate with the helper. URLs passed to this helper should not include scheme or host.
type Helper ¶
type Helper struct {
// contains filtered or unexported fields
}
Helper is the result of registering a helper. It can be used by tests to spawn the helper.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry keeps track of helpers.
The zero value is ready to use.
func (*Registry) AddFlag ¶
AddFlag adds the command-line flag used to communicate between Control and the helper to the flag set. Typically flag.CommandLine is used, and this should be called from TestMain before flag.Parse.
func (*Registry) Register ¶
Register a helper in the registry.
This should be called from a top-level variable assignment.
Register will panic if the name is already registered.
func (*Registry) RunIfNeeded ¶
func (r *Registry) RunIfNeeded()
RunIfNeeded passes execution to the helper if the right command-line flag was seen. This should be called from TestMain after flag.Parse. If running as the helper, the call will not return.