diff --git a/core/handlers/v2/simulation_handler.go b/core/handlers/v2/simulation_handler.go index 9eb60e7ae..28965b8ab 100644 --- a/core/handlers/v2/simulation_handler.go +++ b/core/handlers/v2/simulation_handler.go @@ -34,6 +34,10 @@ func (this *SimulationHandler) RegisterRoutes(mux *bone.Mux, am *handlers.AuthHa negroni.HandlerFunc(am.RequireTokenAuthentication), negroni.HandlerFunc(this.Put), )) + mux.Put("/api/v2/simulation/:id", negroni.New( + negroni.HandlerFunc(am.RequireTokenAuthentication), + negroni.HandlerFunc(this.PutWithId), + )) mux.Post("/api/v2/simulation", negroni.New( negroni.HandlerFunc(am.RequireTokenAuthentication), negroni.HandlerFunc(this.Post), @@ -42,6 +46,10 @@ func (this *SimulationHandler) RegisterRoutes(mux *bone.Mux, am *handlers.AuthHa negroni.HandlerFunc(am.RequireTokenAuthentication), negroni.HandlerFunc(this.Delete), )) + mux.Delete("/api/v2/simulation/:id", negroni.New( + negroni.HandlerFunc(am.RequireTokenAuthentication), + negroni.HandlerFunc(this.DeleteWithId), + )) mux.Options("/api/v2/simulation", negroni.New( negroni.HandlerFunc(this.Options), )) @@ -84,6 +92,17 @@ func (this *SimulationHandler) Put(w http.ResponseWriter, req *http.Request, nex this.Get(w, req, next) } +func (this *SimulationHandler) PutWithId(w http.ResponseWriter, req *http.Request, next http.HandlerFunc) { + id := bone.GetValue(req, "id") + fmt.Printf("%s\n", id) + err := this.addSingleSimulation(w, req, true, id) + if err != nil { + return + } + + this.Get(w, req, next) +} + func (this *SimulationHandler) Post(w http.ResponseWriter, req *http.Request, next http.HandlerFunc) { err := this.addSimulation(w, req, false) if err != nil { @@ -99,6 +118,37 @@ func (this *SimulationHandler) Delete(w http.ResponseWriter, req *http.Request, this.Get(w, req, next) } +func (this *SimulationHandler) DeleteWithId(w http.ResponseWriter, req *http.Request, next http.HandlerFunc) { + id := bone.GetValue(req, "id") + + simulationView, _ := this.Hoverfly.GetSimulation() + + var filtered []RequestMatcherResponsePairViewV5 + for _, value := range simulationView.DataViewV5.RequestResponsePairs { + if value.Id == "" { + filtered = append(filtered, value) + } else if value.Id != id { + filtered = append(filtered, value) + } + } + simulationView.RequestResponsePairs = filtered + this.Hoverfly.DeleteSimulation() + + result := this.Hoverfly.PutSimulation(simulationView) + if result.Err != nil { + handlers.WriteErrorResponse(w, "An error occurred: "+result.Err.Error(), http.StatusInternalServerError) + return + } + if len(result.WarningMessages) > 0 { + bytes, _ := util.JSONMarshal(result) + + handlers.WriteResponse(w, bytes) + return + } + + this.Get(w, req, next) +} + func (this *SimulationHandler) Options(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { w.Header().Add("Allow", "OPTIONS, GET, PUT, DELETE") handlers.WriteResponse(w, []byte("")) @@ -144,3 +194,49 @@ func (this *SimulationHandler) addSimulation(w http.ResponseWriter, req *http.Re } return nil } + +func (this *SimulationHandler) addSingleSimulation(w http.ResponseWriter, req *http.Request, overrideExisting bool, id string) error { + body, _ := ioutil.ReadAll(req.Body) + + simulationSingleViewV1, err := NewSimulationSingleViewFromRequestBody(body) + if err != nil { + handlers.WriteErrorResponse(w, err.Error(), http.StatusBadRequest) + return err + } + + fmt.Printf("요청값 %+v\n\n\n\n", simulationSingleViewV1) + + simulationView, _ := this.Hoverfly.GetSimulation() + + var filtered []RequestMatcherResponsePairViewV5 + + for _, value := range simulationView.DataViewV5.RequestResponsePairs { + if value.Id == "" { + filtered = append(filtered, value) + } else if value.Id != id { + filtered = append(filtered, value) + } + } + simulationSingleViewV1.Id = id + filtered = append(filtered, simulationSingleViewV1.RequestMatcherResponsePairViewV5) + fmt.Printf("%+v|%+v\n", filtered, filtered[0].Id) + simulationView.DataViewV5.RequestResponsePairs = filtered + + this.Hoverfly.DeleteSimulation() + result := this.Hoverfly.PutSimulation(simulationView) + if result.Err != nil { + log.WithFields(log.Fields{ + "body": string(body), + }).Debug(result.Err.Error()) + + handlers.WriteErrorResponse(w, "An error occurred: "+result.Err.Error(), http.StatusInternalServerError) + return result.Err + } + if len(result.WarningMessages) > 0 { + bytes, _ := util.JSONMarshal(result) + + handlers.WriteResponse(w, bytes) + return fmt.Errorf("import simulation result has warnings") + } + return nil +} diff --git a/core/handlers/v2/simulation_views.go b/core/handlers/v2/simulation_views.go index 9f8c1f8cd..dc9f524e3 100644 --- a/core/handlers/v2/simulation_views.go +++ b/core/handlers/v2/simulation_views.go @@ -8,11 +8,28 @@ import ( "strings" - "github.com/SpectoLabs/hoverfly/core/handlers/v1" + v1 "github.com/SpectoLabs/hoverfly/core/handlers/v1" log "github.com/sirupsen/logrus" "github.com/xeipuuv/gojsonschema" ) +func NewSimulationSingleViewFromRequestBody(requestBody []byte) (SimulationSingleViewV1, error) { + var simulationSingleViewV1 SimulationSingleViewV1 + + jsonMap := make(map[string]interface{}) + + if err := json.Unmarshal(requestBody, &jsonMap); err != nil { + return SimulationSingleViewV1{}, errors.New("Invalid JSON") + } + + err := json.Unmarshal(requestBody, &simulationSingleViewV1) + if err != nil { + return SimulationSingleViewV1{}, err + } + + return simulationSingleViewV1, nil +} + func NewSimulationViewFromRequestBody(requestBody []byte) (SimulationViewV5, error) { var simulationView SimulationViewV5 @@ -43,50 +60,6 @@ func NewSimulationViewFromRequestBody(requestBody []byte) (SimulationViewV5, err if err != nil { return SimulationViewV5{}, err } - } else if schemaVersion == "v4" || schemaVersion == "v3" { - err := ValidateSimulation(jsonMap, SimulationViewV4Schema) - if err != nil { - return simulationView, errors.New(fmt.Sprintf("Invalid %s simulation: ", schemaVersion) + err.Error()) - } - - var simulationViewV4 SimulationViewV4 - - err = json.Unmarshal(requestBody, &simulationViewV4) - if err != nil { - return SimulationViewV5{}, err - } - - simulationView = upgradeV4(simulationViewV4) - } else if schemaVersion == "v2" { - err := ValidateSimulation(jsonMap, SimulationViewV2Schema) - if err != nil { - return simulationView, errors.New(fmt.Sprintf("Invalid %s simulation: ", schemaVersion) + err.Error()) - } - - var simulationViewV2 SimulationViewV2 - - err = json.Unmarshal(requestBody, &simulationViewV2) - if err != nil { - return SimulationViewV5{}, err - } - - simulationView = upgradeV2(simulationViewV2) - } else if schemaVersion == "v1" { - err := ValidateSimulation(jsonMap, SimulationViewV1Schema) - if err != nil { - return simulationView, errors.New("Invalid v1 simulation: " + err.Error()) - } - - var simulationViewV1 SimulationViewV1 - - err = json.Unmarshal(requestBody, &simulationViewV1) - if err != nil { - return SimulationViewV5{}, err - } - - simulationView = upgradeV1(simulationViewV1) - } else { - return simulationView, fmt.Errorf("Invalid simulation: schema version %v is not supported by this version of Hoverfly, you may need to update Hoverfly", schemaVersion) } return simulationView, nil diff --git a/core/handlers/v2/simulation_views_v5.go b/core/handlers/v2/simulation_views_v5.go index 4b5579994..83d1d8063 100644 --- a/core/handlers/v2/simulation_views_v5.go +++ b/core/handlers/v2/simulation_views_v5.go @@ -4,6 +4,10 @@ import ( "github.com/SpectoLabs/hoverfly/core/interfaces" ) +type SimulationSingleViewV1 struct { + RequestMatcherResponsePairViewV5 `json:"data"` +} + type SimulationViewV5 struct { DataViewV5 `json:"data"` MetaView `json:"meta"` @@ -19,6 +23,7 @@ type DataViewV5 struct { type RequestMatcherResponsePairViewV5 struct { RequestMatcher RequestMatcherViewV5 `json:"request"` Response ResponseDetailsViewV5 `json:"response"` + Id string } // RequestDetailsView is used when marshalling and unmarshalling RequestDetails diff --git a/core/models/request_matcher.go b/core/models/request_matcher.go index b5aaac5cd..6d104d123 100644 --- a/core/models/request_matcher.go +++ b/core/models/request_matcher.go @@ -2,6 +2,7 @@ package models import ( "encoding/json" + v2 "github.com/SpectoLabs/hoverfly/core/handlers/v2" "github.com/SpectoLabs/hoverfly/core/matching/matchers" "github.com/SpectoLabs/hoverfly/core/util" @@ -144,6 +145,7 @@ func getViewFromRequestFieldMatcher(matcher *RequestFieldMatchers) *v2.MatcherVi type RequestMatcherResponsePair struct { RequestMatcher RequestMatcher Response ResponseDetails + Id string } func NewRequestMatcherResponsePairFromView(view *v2.RequestMatcherResponsePairViewV5) *RequestMatcherResponsePair { @@ -160,6 +162,7 @@ func NewRequestMatcherResponsePairFromView(view *v2.RequestMatcherResponsePairVi RequiresState: view.RequestMatcher.RequiresState, }, Response: NewResponseDetailsFromResponse(view.Response), + Id: view.Id, } } @@ -240,6 +243,7 @@ func (this *RequestMatcherResponsePair) BuildView() v2.RequestMatcherResponsePai RequiresState: this.RequestMatcher.RequiresState, }, Response: this.Response.ConvertToResponseDetailsViewV5(), + Id: this.Id, } } diff --git a/docs/conf.py b/docs/conf.py index bf4318795..491853709 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -12,7 +12,7 @@ copyright = '2023, SpectoLabs' author = 'SpectoLabs' -version = 'v1.9.1' +version = 'v1.9.2' # The full version, including alpha/beta/rc tags. release = version