mtest: implement NewCtx and Run, and use them in mnet and mhttp's tests

This commit is contained in:
Brian Picciano 2019-02-02 20:58:18 -05:00
parent c6e29715b0
commit f783b62f6f
4 changed files with 118 additions and 65 deletions

View File

@ -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) {

View File

@ -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)
}
})
}

View File

@ -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)
}
}

18
mtest/mtest_test.go Normal file
View File

@ -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)
}
})
}