From 00bb4d1257c208d12940bff4791276a531be55ba Mon Sep 17 00:00:00 2001 From: Tolga Ceylan Date: Fri, 13 Apr 2018 10:35:57 -0700 Subject: [PATCH] fn: empty body tests for cold and hot (json/http) (#941) --- api/server/runner_test.go | 74 +++++++++++++++++++++++++++ images/fn-test-utils/fn-test-utils.go | 6 ++- 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/api/server/runner_test.go b/api/server/runner_test.go index 5a6ae5553..84e7a4740 100644 --- a/api/server/runner_test.go +++ b/api/server/runner_test.go @@ -315,6 +315,80 @@ func TestRouteRunnerIOPipes(t *testing.T) { } } +func TestRouteRunnerExecEmptyBody(t *testing.T) { + buf := setLogBuffer() + isFailure := false + + defer func() { + if isFailure { + t.Log(buf.String()) + } + }() + + rCfg := map[string]string{"ENABLE_HEADER": "yes", "ENABLE_FOOTER": "yes"} // enable container start/end header/footer + rHdr := map[string][]string{"X-Function": {"Test"}} + rImg := "fnproject/fn-test-utils" + + app := &models.App{Name: "soup"} + app.SetDefaults() + ds := datastore.NewMockInit( + []*models.App{app}, + []*models.Route{ + {Path: "/cold", AppID: app.ID, Image: rImg, Type: "sync", Memory: 64, Timeout: 10, IdleTimeout: 20, Headers: rHdr, Config: rCfg}, + {Path: "/hothttp", AppID: app.ID, Image: rImg, Type: "sync", Format: "http", Memory: 64, Timeout: 10, IdleTimeout: 20, Headers: rHdr, Config: rCfg}, + {Path: "/hotjson", AppID: app.ID, Image: rImg, Type: "sync", Format: "json", Memory: 64, Timeout: 10, IdleTimeout: 20, Headers: rHdr, Config: rCfg}, + }, + ) + + rnr, cancelrnr := testRunner(t, ds) + defer cancelrnr() + + srv := testServer(ds, &mqs.Mock{}, ds, rnr, ServerTypeFull) + + expHeaders := map[string][]string{"X-Function": {"Test"}} + emptyBody := `{"echoContent": "_TRX_ID_", "isDebug": true, "isEmptyBody": true}` + + // Test hot cases twice to rule out hot-containers corrupting next request. + testCases := []struct { + path string + }{ + {"/r/soup/cold/"}, + {"/r/soup/hothttp"}, + {"/r/soup/hothttp"}, + {"/r/soup/hotjson"}, + {"/r/soup/hotjson"}, + } + + for i, test := range testCases { + trx := fmt.Sprintf("_trx_%d_", i) + body := strings.NewReader(strings.Replace(emptyBody, "_TRX_ID_", trx, 1)) + _, rec := routerRequest(t, srv.Router, "GET", test.path, body) + respBytes, _ := ioutil.ReadAll(rec.Body) + respBody := string(respBytes) + maxBody := len(respBody) + if maxBody > 1024 { + maxBody = 1024 + } + + if rec.Code != http.StatusOK { + isFailure = true + t.Errorf("Test %d: Expected status code to be %d but was %d. body: %s", + i, http.StatusOK, rec.Code, respBody[:maxBody]) + } else if len(respBytes) != 0 { + isFailure = true + t.Errorf("Test %d: Expected empty body but got %d. body: %s", + i, len(respBytes), respBody[:maxBody]) + } + + for name, header := range expHeaders { + if header[0] != rec.Header().Get(name) { + isFailure = true + t.Errorf("Test %d: Expected header `%s` to be %s but was %s. body: %s", + i, name, header[0], rec.Header().Get(name), respBody) + } + } + } +} func TestRouteRunnerExecution(t *testing.T) { buf := setLogBuffer() isFailure := false diff --git a/images/fn-test-utils/fn-test-utils.go b/images/fn-test-utils/fn-test-utils.go index 033de238b..c61619f12 100644 --- a/images/fn-test-utils/fn-test-utils.go +++ b/images/fn-test-utils/fn-test-utils.go @@ -60,6 +60,8 @@ type AppRequest struct { PostOutGarbage string `json:"postOutGarbage,omitempty"` // spit this out in stderr after processing each request PostErrGarbage string `json:"postErrGarbage,omitempty"` + // test empty body + IsEmptyBody bool `json:"isEmptyBody,omitempty"` // TODO: simulate slow read/slow write // TODO: simulate partial IO write/read // TODO: simulate high cpu usage (async and sync) @@ -133,7 +135,9 @@ func finalizeRequest(out *fdkresponse, req *AppRequest, resp *AppResponse) { out.JasonContentType = req.JasonContentType } - json.NewEncoder(out).Encode(resp) + if !req.IsEmptyBody { + json.NewEncoder(out).Encode(resp) + } } func processRequest(ctx context.Context, in io.Reader) (*AppRequest, *AppResponse) {