func TestImportImportRequestResponsePairs_CanImportAMultiplePairs(t *testing.T) { RegisterTestingT(t) cache := cache.NewInMemoryCache() cfg := Configuration{Webserver: false} requestMatcher := matching.RequestMatcher{RequestCache: cache, Webserver: &cfg.Webserver} hv := Hoverfly{RequestCache: cache, Cfg: &cfg, RequestMatcher: requestMatcher} RegisterTestingT(t) originalPair1 := v1.RequestResponsePairView{ Response: v1.ResponseDetailsView{ Status: 200, Body: "hello_world", EncodedBody: false, Headers: map[string][]string{"Hoverfly": []string{"testing"}}, }, Request: v1.RequestDetailsView{ Path: StringToPointer("/"), Method: StringToPointer("GET"), Destination: StringToPointer("/"), Scheme: StringToPointer("scheme"), Query: StringToPointer(""), Body: StringToPointer(""), Headers: map[string][]string{"Hoverfly": []string{"testing"}}}} originalPair2 := originalPair1 originalPair2.Request.Path = StringToPointer("/new/path") originalPair3 := originalPair1 originalPair3.Request.Path = StringToPointer("/newer/path") hv.ImportRequestResponsePairViews([]interfaces.RequestResponsePair{originalPair1, originalPair2, originalPair3}) pairBytes, err := cache.Get([]byte("9b114df98da7f7e2afdc975883dab4f2")) Expect(err).To(BeNil()) decodedPair1, err := models.NewRequestResponsePairFromBytes(pairBytes) Expect(err).To(BeNil()) Expect(*decodedPair1).To(Equal(models.NewRequestResponsePairFromRequestResponsePairView(originalPair1))) pairBytes, err = cache.Get([]byte("9c03e4af1f30542ff079a712bddad602")) Expect(err).To(BeNil()) decodedPair2, err := models.NewRequestResponsePairFromBytes(pairBytes) Expect(err).To(BeNil()) Expect(*decodedPair2).To(Equal(models.NewRequestResponsePairFromRequestResponsePairView(originalPair2))) pairBytes, err = cache.Get([]byte("fd099332afee48101edb7441b098cd4a")) Expect(err).To(BeNil()) decodedPair3, err := models.NewRequestResponsePairFromBytes(pairBytes) Expect(err).To(BeNil()) Expect(*decodedPair3).To(Equal(models.NewRequestResponsePairFromRequestResponsePairView(originalPair3))) }
func ExecuteMiddlewareRemotely(middleware string, pair models.RequestResponsePair) (models.RequestResponsePair, error) { pairViewBytes, err := json.Marshal(pair.ConvertToRequestResponsePairView()) req, err := http.NewRequest("POST", middleware, bytes.NewBuffer(pairViewBytes)) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), }).Error("Error when building request to remote middleware") return pair, err } resp, err := http.DefaultClient.Do(req) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), }).Error("Error when communicating with remote middleware") return pair, err } if resp.StatusCode != 200 { log.Error("Remote middleware did not process payload") return pair, errors.New("Error when communicating with remote middleware") } returnedPairViewBytes, err := ioutil.ReadAll(resp.Body) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), }).Error("Error when process response from remote middleware") return pair, err } var newPairView views.RequestResponsePairView err = json.Unmarshal(returnedPairViewBytes, &newPairView) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), }).Error("Error when trying to serialize response from remote middleware") return pair, err } return models.NewRequestResponsePairFromRequestResponsePairView(newPairView), nil }
// ExecuteMiddleware - takes command (middleware string) and payload, which is passed to middleware func ExecuteMiddlewareLocally(middlewares string, pair models.RequestResponsePair) (models.RequestResponsePair, error) { mws := strings.Split(middlewares, "|") var cmdList []*exec.Cmd for _, v := range mws { commands := strings.Split(strings.TrimSpace(v), " ") cmd := exec.Command(commands[0], commands[1:]...) cmdList = append(cmdList, cmd) } // getting payload pairViewBytes, err := json.Marshal(pair.ConvertToRequestResponsePairView()) if log.GetLevel() == log.DebugLevel { log.WithFields(log.Fields{ "middlewares": mws, "count": len(mws), "payload": string(pairViewBytes), }).Debug("preparing to modify payload") } if err != nil { log.WithFields(log.Fields{ "error": err.Error(), }).Error("Failed to marshal json") return pair, err } // cmdList[0].Stdin = bytes.NewReader(pairViewBytes) // Run the pipeline mwOutput, stderr, err := Pipeline(cmdList...) // middleware failed to execute if err != nil { if len(stderr) > 0 { log.WithFields(log.Fields{ "sdtderr": string(stderr), "error": err.Error(), }).Error("Middleware error") } else { log.WithFields(log.Fields{ "error": err.Error(), }).Error("Middleware error") } return pair, err } // log stderr, middleware executed successfully if len(stderr) > 0 { log.WithFields(log.Fields{ "sdtderr": string(stderr), }).Info("Information from middleware") } if len(mwOutput) > 0 { var newPairView views.RequestResponsePairView err = json.Unmarshal(mwOutput, &newPairView) if err != nil { log.WithFields(log.Fields{ "mwOutput": string(mwOutput), "error": err.Error(), }).Error("Failed to unmarshal JSON from middleware") } else { if log.GetLevel() == log.DebugLevel { log.WithFields(log.Fields{ "middlewares": middlewares, "count": len(middlewares), "payload": string(mwOutput), }).Debug("payload after modifications") } // payload unmarshalled into RequestResponsePair struct, returning it return models.NewRequestResponsePairFromRequestResponsePairView(newPairView), nil } } else { log.WithFields(log.Fields{ "mwOutput": string(mwOutput), }).Warn("No response from middleware.") } return pair, nil }
// ImportRequestResponsePairViews - a function to save given pairs into the database. func (hf *Hoverfly) ImportRequestResponsePairViews(pairViews []views.RequestResponsePairView) error { if len(pairViews) > 0 { success := 0 failed := 0 for _, pairView := range pairViews { // Convert PayloadView back to Payload for internal storage pair := models.NewRequestResponsePairFromRequestResponsePairView(pairView) if len(pair.Request.Headers) == 0 { pair.Request.Headers = make(map[string][]string) } if _, present := pair.Request.Headers["Content-Type"]; !present { // sniffing content types if isJSON(pair.Request.Body) { pair.Request.Headers["Content-Type"] = []string{"application/json"} } else { ct := http.DetectContentType([]byte(pair.Request.Body)) pair.Request.Headers["Content-Type"] = []string{ct} } } pairBytes, err := pair.Encode() if err != nil { log.WithFields(log.Fields{ "error": err.Error(), }).Error("Failed to encode payload") failed++ } else { // hook var en Entry en.ActionType = ActionTypeRequestCaptured en.Message = "imported" en.Time = time.Now() en.Data = pairBytes if err := hf.Hooks.Fire(ActionTypeRequestCaptured, &en); err != nil { log.WithFields(log.Fields{ "error": err.Error(), "message": en.Message, "actionType": ActionTypeRequestCaptured, }).Error("failed to fire hook") } err := hf.RequestMatcher.SaveRequestResponsePair(&pair) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), }).Error("Failed to save payload") } if err == nil { success++ } else { failed++ } } } log.WithFields(log.Fields{ "total": len(pairViews), "successful": success, "failed": failed, }).Info("payloads imported") return nil } return fmt.Errorf("Bad request. Nothing to import!") }
// ImportRequestResponsePairViews - a function to save given pairs into the database. func (hf *Hoverfly) ImportRequestResponsePairViews(pairViews []interfaces.RequestResponsePair) error { if len(pairViews) > 0 { success := 0 failed := 0 for _, pairView := range pairViews { if pairView.GetRequest().GetRequestType() != nil && *pairView.GetRequest().GetRequestType() == *StringToPointer("template") { responseDetails := models.NewResponseDetailsFromResponse(pairView.GetResponse()) requestTemplate := matching.RequestTemplate{ Path: pairView.GetRequest().GetPath(), Method: pairView.GetRequest().GetMethod(), Destination: pairView.GetRequest().GetDestination(), Scheme: pairView.GetRequest().GetScheme(), Query: pairView.GetRequest().GetQuery(), Body: pairView.GetRequest().GetBody(), Headers: pairView.GetRequest().GetHeaders(), } requestTemplateResponsePair := matching.RequestTemplateResponsePair{ RequestTemplate: requestTemplate, Response: responseDetails, } hf.RequestMatcher.TemplateStore = append(hf.RequestMatcher.TemplateStore, requestTemplateResponsePair) success++ continue } // Convert PayloadView back to Payload for internal storage pair := models.NewRequestResponsePairFromRequestResponsePairView(pairView) if len(pair.Request.Headers) == 0 { pair.Request.Headers = make(map[string][]string) } if _, present := pair.Request.Headers["Content-Type"]; !present { // sniffing content types if isJSON(pair.Request.Body) { pair.Request.Headers["Content-Type"] = []string{"application/json"} } else { ct := http.DetectContentType([]byte(pair.Request.Body)) pair.Request.Headers["Content-Type"] = []string{ct} } } pairBytes, err := pair.Encode() if err != nil { log.WithFields(log.Fields{ "error": err.Error(), }).Error("Failed to encode payload") failed++ } else { // hook var en Entry en.ActionType = ActionTypeRequestCaptured en.Message = "imported" en.Time = time.Now() en.Data = pairBytes if err := hf.Hooks.Fire(ActionTypeRequestCaptured, &en); err != nil { log.WithFields(log.Fields{ "error": err.Error(), "message": en.Message, "actionType": ActionTypeRequestCaptured, }).Error("failed to fire hook") } err := hf.RequestMatcher.SaveRequestResponsePair(&pair) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), }).Error("Failed to save payload") } if err == nil { success++ } else { failed++ } } } log.WithFields(log.Fields{ "total": len(pairViews), "successful": success, "failed": failed, }).Info("payloads imported") return nil } return nil }
// ExecuteMiddleware - takes command (middleware string) and payload, which is passed to middleware func (this Middleware) executeMiddlewareLocally(pair models.RequestResponsePair) (models.RequestResponsePair, error) { var commandAndArgs []string if this.Binary == "" { commandAndArgs = strings.Split(strings.TrimSpace(this.FullCommand), " ") } else { commandAndArgs = []string{this.Binary, this.Script.Name()} } middlewareCommand := exec.Command(commandAndArgs[0], commandAndArgs[1:]...) // getting payload pairViewBytes, err := json.Marshal(pair.ConvertToRequestResponsePairView()) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), }).Error("Failed to marshal json") return pair, err } if log.GetLevel() == log.DebugLevel { log.WithFields(log.Fields{ "middleware": this.FullCommand, "stdin": string(pairViewBytes), }).Debug("preparing to modify payload") } var stdout bytes.Buffer var stderr bytes.Buffer // Redirect standard streams middlewareCommand.Stdin = bytes.NewReader(pairViewBytes) middlewareCommand.Stdout = &stdout middlewareCommand.Stderr = &stderr if err := middlewareCommand.Start(); err != nil { log.WithFields(log.Fields{ "sdtdout": string(stdout.Bytes()), "sdtderr": string(stderr.Bytes()), "error": err.Error(), }).Error("Middleware failed to start") return pair, err } if err := middlewareCommand.Wait(); err != nil { log.WithFields(log.Fields{ "sdtdout": string(stdout.Bytes()), "sdtderr": string(stderr.Bytes()), "error": err.Error(), }).Error("Middleware failed to stop successfully") return pair, err } // log stderr, middleware executed successfully if len(stderr.Bytes()) > 0 { log.WithFields(log.Fields{ "sdtderr": string(stderr.Bytes()), }).Info("Information from middleware") } if len(stdout.Bytes()) > 0 { var newPairView v2.RequestResponsePairView err = json.Unmarshal(stdout.Bytes(), &newPairView) if err != nil { log.WithFields(log.Fields{ "stdout": string(stdout.Bytes()), "error": err.Error(), }).Error("Failed to unmarshal JSON from middleware") } else { if log.GetLevel() == log.DebugLevel { log.WithFields(log.Fields{ "middleware": this.FullCommand, "payload": string(stdout.Bytes()), }).Debug("payload after modifications") } // payload unmarshalled into RequestResponsePair struct, returning it return models.NewRequestResponsePairFromRequestResponsePairView(newPairView), nil } } else { log.WithFields(log.Fields{ "stdout": string(stdout.Bytes()), }).Warn("No response from middleware.") } return pair, nil }