diff --git a/integrations/kfasthttp/fasthttp.go b/integrations/kfasthttp/fasthttp.go index 192f15f5..47b7c35d 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,27 @@ 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 + header := make(http.Header) + for key, v := range r.Header { + header[key] = v + } 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: 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 657135e1..bf2ad717 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 { @@ -62,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 @@ -103,9 +106,25 @@ func mw(k *keploy.Keploy) gin.HandlerFunc { } c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(reqBody)) // Reset - resp := captureRespGin(c) + 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) - 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: header, + Body: string(reqBody), + } + + resp := captureRespGin(c) + keploy.CaptureHttpTC(k, c.Request.Context(), req, keploy.UrlPath(r.URL.Path, params), resp, params) } } 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 diff --git a/keploy/router.go b/keploy/router.go index 1bff02d1..ef7d664f 100644 --- a/keploy/router.go +++ b/keploy/router.go @@ -33,10 +33,30 @@ 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 + + header := make(http.Header) + for key, v := range r.Header { + header[key] = v + } + + 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: header, + Body: string(reqBody), + } + router.SetResponseWriter(writer) router.SetRequest(r) @@ -80,7 +100,6 @@ func Middleware(k *Keploy, router Router) error { return err } - params := router.GetURLParams() - CaptureHttpTC(k, r, reqBody, resp, params) + CaptureHttpTC(k, router.GetRequest().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) diff --git a/pkg/keploy/mode.go b/pkg/keploy/mode.go index beab479e..b623312f 100644 --- a/pkg/keploy/mode.go +++ b/pkg/keploy/mode.go @@ -71,7 +71,14 @@ 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 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") + } + } return kctx.(*Context), nil }