diff --git a/mhttp/mhttp_test.go b/mhttp/mhttp_test.go index 85edc8c..621ca10 100644 --- a/mhttp/mhttp_test.go +++ b/mhttp/mhttp_test.go @@ -8,45 +8,32 @@ import ( "net/http/httptest" . "testing" - "github.com/mediocregopher/mediocre-go-lib/mctx" - "github.com/mediocregopher/mediocre-go-lib/mlog" - "github.com/mediocregopher/mediocre-go-lib/mrun" + "github.com/mediocregopher/mediocre-go-lib/mtest" "github.com/mediocregopher/mediocre-go-lib/mtest/massert" ) func TestMListenAndServe(t *T) { - // TODO mtest.NewCtx - ctx := mctx.ChildOf(mctx.New(), "test") - logger := mlog.From(ctx) - logger.SetMaxLevel(mlog.DebugLevel) - mlog.CtxSet(ctx, logger) + ctx := mtest.NewCtx() - h := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + srv := MListenAndServe(ctx, http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { io.Copy(rw, r.Body) + })) + + mtest.Run(ctx, t, func() { + body := bytes.NewBufferString("HELLO") + resp, err := http.Post("http://"+srv.Addr, "text/plain", body) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + + respBody, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } else if string(respBody) != "HELLO" { + t.Fatalf("unexpected respBody: %q", respBody) + } }) - - srv := MListenAndServe(ctx, h) - if err := mrun.Start(ctx); err != nil { - t.Fatal(err) - } - - body := bytes.NewBufferString("HELLO") - resp, err := http.Post("http://"+srv.Addr, "text/plain", body) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - - respBody, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } else if string(respBody) != "HELLO" { - t.Fatalf("unexpected respBody: %q", respBody) - } - - if err := mrun.Stop(ctx); err != nil { - t.Fatal(err) - } } func TestAddXForwardedFor(t *T) { diff --git a/mnet/mnet_test.go b/mnet/mnet_test.go index 5c50389..5c7ba58 100644 --- a/mnet/mnet_test.go +++ b/mnet/mnet_test.go @@ -6,10 +6,7 @@ import ( "net" . "testing" - "github.com/mediocregopher/mediocre-go-lib/mcfg" - "github.com/mediocregopher/mediocre-go-lib/mctx" - "github.com/mediocregopher/mediocre-go-lib/mlog" - "github.com/mediocregopher/mediocre-go-lib/mrun" + "github.com/mediocregopher/mediocre-go-lib/mtest" "github.com/mediocregopher/mediocre-go-lib/mtest/massert" ) @@ -39,39 +36,26 @@ func TestIsReservedIP(t *T) { } func TestMListen(t *T) { - // TODO mtest.NewCtx - ctx := mctx.ChildOf(mctx.New(), "test") - logger := mlog.From(ctx) - logger.SetMaxLevel(mlog.DebugLevel) - mlog.CtxSet(ctx, logger) - + ctx := mtest.NewCtx() l := MListen(ctx, "", "") - if err := mcfg.Populate(ctx, nil); err != nil { - t.Fatal(err) - } else if err := mrun.Start(ctx); err != nil { - t.Fatal(err) - } + mtest.Run(ctx, t, func() { + go func() { + conn, err := net.Dial("tcp", l.Addr().String()) + if err != nil { + t.Fatal(err) + } else if _, err = fmt.Fprint(conn, "hello world"); err != nil { + t.Fatal(err) + } + conn.Close() + }() - go func() { - conn, err := net.Dial("tcp", l.Addr().String()) + conn, err := l.Accept() if err != nil { t.Fatal(err) - } else if _, err = fmt.Fprint(conn, "hello world"); err != nil { + } else if b, err := ioutil.ReadAll(conn); err != nil { t.Fatal(err) + } else if string(b) != "hello world" { + t.Fatalf("read %q from conn", b) } - conn.Close() - }() - - conn, err := l.Accept() - if err != nil { - t.Fatal(err) - } else if b, err := ioutil.ReadAll(conn); err != nil { - t.Fatal(err) - } else if string(b) != "hello world" { - t.Fatalf("read %q from conn", b) - } - - if err := mrun.Stop(ctx); err != nil { - t.Fatal(err) - } + }) } diff --git a/mtest/mtest.go b/mtest/mtest.go index 8ba2cd6..8f20c76 100644 --- a/mtest/mtest.go +++ b/mtest/mtest.go @@ -1,2 +1,66 @@ // Package mtest implements functionality useful for testing. package mtest + +import ( + "testing" + + "github.com/mediocregopher/mediocre-go-lib/mcfg" + "github.com/mediocregopher/mediocre-go-lib/mctx" + "github.com/mediocregopher/mediocre-go-lib/mlog" + "github.com/mediocregopher/mediocre-go-lib/mrun" +) + +type ctxKey int + +// NewCtx creates and returns a root Context suitable for testing. +func NewCtx() mctx.Context { + ctx := mctx.New() + mlog.From(ctx).SetMaxLevel(mlog.DebugLevel) + return ctx +} + +// SetEnv sets the given environment variable on the given Context, such that it +// will be used as if it was a real environment variable when the Run function +// from this package is called. +func SetEnv(ctx mctx.Context, key, val string) { + mctx.GetSetMutableValue(ctx, false, ctxKey(0), func(i interface{}) interface{} { + m, _ := i.(map[string]string) + if m == nil { + m = map[string]string{} + } + m[key] = val + return m + }) +} + +// Run performs the following using the given Context: +// +// - Calls mcfg.Populate using any variables set by SetEnv. +// +// - Calls mrun.Start +// +// - Calls the passed in body callback. +// +// - Calls mrun.Stop +// +// The intention is that Run is used within a test on a Context created via +// NewCtx, after any setup functions have been called (e.g. mnet.MListen). +func Run(ctx mctx.Context, t *testing.T, body func()) { + envMap, _ := mctx.MutableValue(ctx, ctxKey(0)).(map[string]string) + env := make([]string, 0, len(envMap)) + for key, val := range envMap { + env = append(env, key+"="+val) + } + + if err := mcfg.Populate(ctx, mcfg.SourceEnv{Env: env}); err != nil { + t.Fatal(err) + } else if err := mrun.Start(ctx); err != nil { + t.Fatal(err) + } + + body() + + if err := mrun.Stop(ctx); err != nil { + t.Fatal(err) + } +} diff --git a/mtest/mtest_test.go b/mtest/mtest_test.go new file mode 100644 index 0000000..26bc111 --- /dev/null +++ b/mtest/mtest_test.go @@ -0,0 +1,18 @@ +package mtest + +import ( + . "testing" + + "github.com/mediocregopher/mediocre-go-lib/mcfg" +) + +func TestRun(t *T) { + ctx := NewCtx() + arg := mcfg.RequiredString(ctx, "arg", "Required by this test") + SetEnv(ctx, "ARG", "foo") + Run(ctx, t, func() { + if *arg != "foo" { + t.Fatalf(`arg not set to "foo", is set to %q`, *arg) + } + }) +}