From 0600dcc654f681f8cf72e0ee03dd9dbcff14327e Mon Sep 17 00:00:00 2001 From: Shubham Jain Date: Thu, 6 Apr 2023 20:43:12 +0530 Subject: [PATCH 1/7] fix: add support for setting gin ctx --- integrations/kgin/v1/gin-v1.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/integrations/kgin/v1/gin-v1.go b/integrations/kgin/v1/gin-v1.go index 657135e1..0af1fab0 100644 --- a/integrations/kgin/v1/gin-v1.go +++ b/integrations/kgin/v1/gin-v1.go @@ -53,6 +53,8 @@ func captureRespGin(c *gin.Context) models.HttpResp { func setContextValGin(c *gin.Context, val interface{}) { ctx := context.WithValue(c.Request.Context(), internal.KCTX, val) c.Request = c.Request.WithContext(ctx) + // also set directly on gin context + c.Set(string(internal.KCTX), val) } func mw(k *keploy.Keploy) gin.HandlerFunc { From dadc0b4760db8570eb88cf82577239af8c4f0758 Mon Sep 17 00:00:00 2001 From: Shubham Jain Date: Sat, 8 Apr 2023 22:48:32 +0530 Subject: [PATCH 2/7] fix: capture request before next handler Signed-off-by: Shubham Jain --- integrations/kfasthttp/fasthttp.go | 18 +++++++++++++++--- integrations/kgin/v1/gin-v1.go | 18 +++++++++++++++--- keploy/router.go | 17 +++++++++++++++-- keploy/utils.go | 24 ++++++++---------------- 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/integrations/kfasthttp/fasthttp.go b/integrations/kfasthttp/fasthttp.go index 192f15f5..495b5b81 100644 --- a/integrations/kfasthttp/fasthttp.go +++ b/integrations/kfasthttp/fasthttp.go @@ -54,6 +54,7 @@ func FastHttpMiddleware(k *keploy.Keploy) func(fasthttp.RequestHandler) fasthttp next(c) return } + if id != "" { setContextValFast(c, &internal.Context{ Mode: internal.MODE_TEST, @@ -89,12 +90,23 @@ func FastHttpMiddleware(k *keploy.Keploy) func(fasthttp.RequestHandler) fasthttp } r := &http.Request{} fasthttpadaptor.ConvertRequest(c, r, true) //converting fasthttp request to http - resp := captureResp(c, next) - params := pathParams(c) + // capture request before calling next r = r.WithContext(c) + params := pathParams(c) + req := models.HttpReq{ + Method: models.Method(r.Method), + ProtoMajor: r.ProtoMajor, + ProtoMinor: r.ProtoMinor, + URL: r.URL.String(), + URLParams: keploy.UrlParams(r, params), + Header: r.Header, + Body: string(reqBody), + } + + resp := captureResp(c, next) - keploy.CaptureHttpTC(k, r, reqBody, resp, params) + keploy.CaptureHttpTC(k, r.Context(), req, keploy.UrlPath(r.URL.Path, params), resp, params) }) } } diff --git a/integrations/kgin/v1/gin-v1.go b/integrations/kgin/v1/gin-v1.go index 0af1fab0..1444b46a 100644 --- a/integrations/kgin/v1/gin-v1.go +++ b/integrations/kgin/v1/gin-v1.go @@ -64,7 +64,8 @@ func mw(k *keploy.Keploy) gin.HandlerFunc { } } return func(c *gin.Context) { - id := c.Request.Header.Get("KEPLOY_TEST_ID") + r := c.Request + id := r.Header.Get("KEPLOY_TEST_ID") if id == "" && internal.GetMode() == internal.MODE_TEST { c.Next() return @@ -105,9 +106,20 @@ func mw(k *keploy.Keploy) gin.HandlerFunc { } c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(reqBody)) // Reset - resp := captureRespGin(c) + // capture request before it is processed by the handler params := urlParamsGin(c, k) - keploy.CaptureHttpTC(k, c.Request, reqBody, resp, params) + req := models.HttpReq{ + Method: models.Method(r.Method), + ProtoMajor: r.ProtoMajor, + ProtoMinor: r.ProtoMinor, + URL: r.URL.String(), + URLParams: keploy.UrlParams(r, params), + Header: r.Header, + Body: string(reqBody), + } + + resp := captureRespGin(c) + keploy.CaptureHttpTC(k, r.Context(), req, keploy.UrlPath(r.URL.Path, params), resp, params) } } diff --git a/keploy/router.go b/keploy/router.go index 1bff02d1..5a359c63 100644 --- a/keploy/router.go +++ b/keploy/router.go @@ -33,10 +33,24 @@ func Middleware(k *Keploy, router Router) error { if k == nil || keploy.GetMode() == keploy.MODE_OFF || (keploy.GetMode() == keploy.MODE_TEST && router.GetRequest().Header.Get("KEPLOY_TEST_ID") == "") { return router.Next() } + writer, r, resBody, reqBody, err := ProcessRequest(router.GetResponseWriter(), router.GetRequest(), k) if err != nil { return err } + + // capture request before next handler call + params := router.GetURLParams() + req := models.HttpReq{ + Method: models.Method(r.Method), + ProtoMajor: r.ProtoMajor, + ProtoMinor: r.ProtoMinor, + URL: r.URL.String(), + URLParams: UrlParams(r, params), + Header: r.Header, + Body: string(reqBody), + } + router.SetResponseWriter(writer) router.SetRequest(r) @@ -80,7 +94,6 @@ func Middleware(k *Keploy, router Router) error { return err } - params := router.GetURLParams() - CaptureHttpTC(k, r, reqBody, resp, params) + CaptureHttpTC(k, r.Context(), req, UrlPath(r.URL.Path, params), resp, params) return nil } diff --git a/keploy/utils.go b/keploy/utils.go index 3e3e111c..36ae202c 100644 --- a/keploy/utils.go +++ b/keploy/utils.go @@ -198,8 +198,8 @@ func CaptureGrpcTC(k *Keploy, grpcCtx context.Context, req models.GrpcReq, resp } -func CaptureHttpTC(k *Keploy, r *http.Request, reqBody []byte, resp models.HttpResp, params map[string]string) { - d := r.Context().Value(keploy.KCTX) +func CaptureHttpTC(k *Keploy, ctx context.Context, req models.HttpReq, uri string, resp models.HttpResp, params map[string]string) { + d := ctx.Value(keploy.KCTX) if d == nil { k.Log.Error("failed to get keploy context") return @@ -207,18 +207,10 @@ func CaptureHttpTC(k *Keploy, r *http.Request, reqBody []byte, resp models.HttpR deps := d.(*keploy.Context) k.Capture(models.TestCaseReq{ - Captured: time.Now().Unix(), - AppID: k.cfg.App.Name, - URI: urlPath(r.URL.Path, params), - HttpReq: models.HttpReq{ - Method: models.Method(r.Method), - ProtoMajor: r.ProtoMajor, - ProtoMinor: r.ProtoMinor, - URL: r.URL.String(), - URLParams: urlParams(r, params), - Header: r.Header, - Body: string(reqBody), - }, + Captured: time.Now().Unix(), + AppID: k.cfg.App.Name, + URI: uri, + HttpReq: req, HttpResp: resp, Deps: deps.Deps, TestCasePath: k.cfg.App.TestPath, @@ -228,7 +220,7 @@ func CaptureHttpTC(k *Keploy, r *http.Request, reqBody []byte, resp models.HttpR }) } -func urlParams(r *http.Request, params map[string]string) map[string]string { +func UrlParams(r *http.Request, params map[string]string) map[string]string { result := params qp := r.URL.Query() for i, j := range qp { @@ -248,7 +240,7 @@ func urlParams(r *http.Request, params map[string]string) map[string]string { return result } -func urlPath(url string, params map[string]string) string { +func UrlPath(url string, params map[string]string) string { res := url for i, j := range params { res = strings.Replace(res, "/"+j+"/", "/:"+i+"/", -1) From 73ddd523b7d723d19d0a4bd49d75d2de1123ca80 Mon Sep 17 00:00:00 2001 From: Shubham Jain Date: Sat, 8 Apr 2023 23:02:50 +0530 Subject: [PATCH 3/7] fix: capture request before next handler Signed-off-by: Shubham Jain --- integrations/kgin/v1/gin-v1.go | 2 +- keploy/router.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/integrations/kgin/v1/gin-v1.go b/integrations/kgin/v1/gin-v1.go index 1444b46a..ea512ec5 100644 --- a/integrations/kgin/v1/gin-v1.go +++ b/integrations/kgin/v1/gin-v1.go @@ -119,7 +119,7 @@ func mw(k *keploy.Keploy) gin.HandlerFunc { } resp := captureRespGin(c) - keploy.CaptureHttpTC(k, r.Context(), req, keploy.UrlPath(r.URL.Path, params), resp, params) + keploy.CaptureHttpTC(k, c.Request.Context(), req, keploy.UrlPath(r.URL.Path, params), resp, params) } } diff --git a/keploy/router.go b/keploy/router.go index 5a359c63..2daa99c7 100644 --- a/keploy/router.go +++ b/keploy/router.go @@ -94,6 +94,6 @@ func Middleware(k *Keploy, router Router) error { return err } - CaptureHttpTC(k, r.Context(), req, UrlPath(r.URL.Path, params), resp, params) + CaptureHttpTC(k, router.GetRequest().Context(), req, UrlPath(r.URL.Path, params), resp, params) return nil } From 94e8ead2652d9d1871c4800efff5d23bf28fffb2 Mon Sep 17 00:00:00 2001 From: Shubham Jain Date: Sat, 8 Apr 2023 23:07:53 +0530 Subject: [PATCH 4/7] fix: capture request before next handler Signed-off-by: Shubham Jain --- integrations/kfasthttp/fasthttp.go | 6 +++++- integrations/kgin/v1/gin-v1.go | 7 ++++++- keploy/router.go | 8 +++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/integrations/kfasthttp/fasthttp.go b/integrations/kfasthttp/fasthttp.go index 495b5b81..47b7c35d 100644 --- a/integrations/kfasthttp/fasthttp.go +++ b/integrations/kfasthttp/fasthttp.go @@ -92,6 +92,10 @@ func FastHttpMiddleware(k *keploy.Keploy) func(fasthttp.RequestHandler) fasthttp fasthttpadaptor.ConvertRequest(c, r, true) //converting fasthttp request to http // capture request before calling next + header := make(http.Header) + for key, v := range r.Header { + header[key] = v + } r = r.WithContext(c) params := pathParams(c) req := models.HttpReq{ @@ -100,7 +104,7 @@ func FastHttpMiddleware(k *keploy.Keploy) func(fasthttp.RequestHandler) fasthttp ProtoMinor: r.ProtoMinor, URL: r.URL.String(), URLParams: keploy.UrlParams(r, params), - Header: r.Header, + Header: header, Body: string(reqBody), } diff --git a/integrations/kgin/v1/gin-v1.go b/integrations/kgin/v1/gin-v1.go index ea512ec5..bf2ad717 100644 --- a/integrations/kgin/v1/gin-v1.go +++ b/integrations/kgin/v1/gin-v1.go @@ -106,6 +106,11 @@ func mw(k *keploy.Keploy) gin.HandlerFunc { } c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(reqBody)) // Reset + header := make(http.Header) + for key, v := range r.Header { + header[key] = v + } + // capture request before it is processed by the handler params := urlParamsGin(c, k) req := models.HttpReq{ @@ -114,7 +119,7 @@ func mw(k *keploy.Keploy) gin.HandlerFunc { ProtoMinor: r.ProtoMinor, URL: r.URL.String(), URLParams: keploy.UrlParams(r, params), - Header: r.Header, + Header: header, Body: string(reqBody), } diff --git a/keploy/router.go b/keploy/router.go index 2daa99c7..ef7d664f 100644 --- a/keploy/router.go +++ b/keploy/router.go @@ -40,6 +40,12 @@ func Middleware(k *Keploy, router Router) error { } // capture request before next handler call + + header := make(http.Header) + for key, v := range r.Header { + header[key] = v + } + params := router.GetURLParams() req := models.HttpReq{ Method: models.Method(r.Method), @@ -47,7 +53,7 @@ func Middleware(k *Keploy, router Router) error { ProtoMinor: r.ProtoMinor, URL: r.URL.String(), URLParams: UrlParams(r, params), - Header: r.Header, + Header: header, Body: string(reqBody), } From 379fc468252674dbbf6a0b92a08a0e54fc115587 Mon Sep 17 00:00:00 2001 From: Shubham Jain Date: Sun, 9 Apr 2023 11:27:58 +0530 Subject: [PATCH 5/7] fix: convert kctx key to string Signed-off-by: Shubham Jain --- pkg/keploy/mode.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/keploy/mode.go b/pkg/keploy/mode.go index beab479e..e498c724 100644 --- a/pkg/keploy/mode.go +++ b/pkg/keploy/mode.go @@ -71,7 +71,12 @@ func GetModeFromContext(ctx context.Context) Mode { func GetState(ctx context.Context) (*Context, error) { kctx := ctx.Value(KCTX) if kctx == nil { - return nil, errors.New("failed to get Keploy context") + // cast to string and check + kctx = ctx.Value(string(KCTX)) + if kctx == nil { + return nil, errors.New("failed to get Keploy context") + } + } return kctx.(*Context), nil } From b2ebdc38f549fe12353232dca21b0f72ffaeade9 Mon Sep 17 00:00:00 2001 From: Shubham Jain Date: Sun, 9 Apr 2023 12:20:27 +0530 Subject: [PATCH 6/7] doc: comment on kctx string conversion Signed-off-by: Shubham Jain --- pkg/keploy/mode.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/keploy/mode.go b/pkg/keploy/mode.go index e498c724..b623312f 100644 --- a/pkg/keploy/mode.go +++ b/pkg/keploy/mode.go @@ -71,7 +71,9 @@ func GetModeFromContext(ctx context.Context) Mode { func GetState(ctx context.Context) (*Context, error) { kctx := ctx.Value(KCTX) if kctx == nil { - // cast to string and check + // cast to string and check again + // this done to avoid the error "cannot use KCTX (type KctxType) as type string in argument to ctx.Value" + // gin context is of type map[string]interface{} and not map[KctxType]interface{} and hence the need to cast to string kctx = ctx.Value(string(KCTX)) if kctx == nil { return nil, errors.New("failed to get Keploy context") From 71af39440146cdea989bbb491378afd226c49ea3 Mon Sep 17 00:00:00 2001 From: Shubham Jain Date: Sun, 9 Apr 2023 12:49:17 +0530 Subject: [PATCH 7/7] fix: initialize result channel in init Signed-off-by: Shubham Jain --- keploy/keploy.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/keploy/keploy.go b/keploy/keploy.go index c3ff3361..2f8b99fe 100644 --- a/keploy/keploy.go +++ b/keploy/keploy.go @@ -30,9 +30,8 @@ import ( ) var ( - // mode = keploy.MODE_OFF - result = make(chan bool, 1) + result chan bool RespChannels = map[string]chan bool{} ) @@ -56,6 +55,7 @@ type GrpcResp struct { // } func init() { + result = make(chan bool, 1) m := keploy.Mode(os.Getenv("KEPLOY_MODE")) if m == "" { return