From aefa76ab43e92255f81064bbfdaf60066416f187 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Fri, 1 Sep 2023 18:25:01 +0300 Subject: [PATCH 1/4] returned api unit tests --- example/stream/client/main.go | 2 +- go.mod | 6 +- go.sum | 10 + gripmock.go | 11 +- stub/actions.go | 45 ++-- stub/api_test.go | 375 ++++++++++++++++++++++++++++++++++ stub/stub.go | 8 +- 7 files changed, 431 insertions(+), 26 deletions(-) create mode 100644 stub/api_test.go diff --git a/example/stream/client/main.go b/example/stream/client/main.go index 26fb2d7f..ed04e29f 100644 --- a/example/stream/client/main.go +++ b/example/stream/client/main.go @@ -128,5 +128,5 @@ func bidirectionalStream(c pb.GripmockClient, wg *sync.WaitGroup) { log.Fatalf("2ds error: %v", err) } } - stream.CloseSend() + _ = stream.CloseSend() } diff --git a/go.mod b/go.mod index b0fb4574..4503a23f 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,10 @@ go 1.21 require ( github.com/goccy/go-yaml v1.11.0 github.com/google/uuid v1.3.0 + github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 github.com/lithammer/fuzzysearch v1.1.8 + github.com/stretchr/testify v1.8.4 github.com/tokopedia/gripmock/protogen v0.0.0 github.com/tokopedia/gripmock/protogen/example v0.0.0 golang.org/x/text v0.12.0 @@ -15,16 +17,18 @@ require ( ) require ( + github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.10.0 // indirect github.com/felixge/httpsnoop v1.0.1 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/gorilla/handlers v1.5.1 // indirect github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.12 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/net v0.14.0 // indirect golang.org/x/sys v0.11.0 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) // this is for generated server to be able to run diff --git a/go.sum b/go.sum index a30c928b..b4037591 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= @@ -30,6 +32,10 @@ github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -82,3 +88,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/gripmock.go b/gripmock.go index 289407cd..da8331b2 100644 --- a/gripmock.go +++ b/gripmock.go @@ -42,7 +42,9 @@ func main() { // for safety output += "/" if _, err := os.Stat(output); os.IsNotExist(err) { - os.Mkdir(output, os.ModePerm) + if err := os.Mkdir(output, os.ModePerm); err != nil { + log.Fatal(err) + } } // run admin stub server @@ -71,9 +73,6 @@ func main() { imports: importDirs, }) - // build the server - //buildServer(output) - // and run run, runerr := runGrpcServer(output) @@ -84,7 +83,9 @@ func main() { log.Fatal(err) case <-term: fmt.Println("Stopping gRPC Server") - run.Process.Kill() + if err := run.Process.Kill(); err != nil { + log.Fatal(err) + } } } diff --git a/stub/actions.go b/stub/actions.go index ab67cb65..0b094417 100644 --- a/stub/actions.go +++ b/stub/actions.go @@ -3,6 +3,7 @@ package stub import ( "bytes" "encoding/json" + "io" "log" "net/http" "os" @@ -39,7 +40,7 @@ func NewApiHandler() *ApiHandler { return &ApiHandler{stubs: storage.New(), convertor: yaml2json.New()} } -func (h *ApiHandler) searchHandle(w http.ResponseWriter, r *http.Request) { +func (h *ApiHandler) SearchHandle(w http.ResponseWriter, r *http.Request) { stub := new(findStubPayload) decoder := json.NewDecoder(r.Body) decoder.UseNumber() @@ -64,15 +65,15 @@ func (h *ApiHandler) searchHandle(w http.ResponseWriter, r *http.Request) { } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(output) + _ = json.NewEncoder(w).Encode(output) } -func (h *ApiHandler) purgeHandle(w http.ResponseWriter, _ *http.Request) { +func (h *ApiHandler) PurgeHandle(w http.ResponseWriter, _ *http.Request) { h.stubs.Purge() w.WriteHeader(204) } -func (h *ApiHandler) listHandle(w http.ResponseWriter, _ *http.Request) { +func (h *ApiHandler) ListHandle(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "application/json") err := json.NewEncoder(w).Encode(h.stubs.Stubs()) if err != nil { @@ -81,27 +82,39 @@ func (h *ApiHandler) listHandle(w http.ResponseWriter, _ *http.Request) { } } -func (h *ApiHandler) addHandle(w http.ResponseWriter, r *http.Request) { - // todo: add supported input array - stub := new(storage.Stub) - decoder := json.NewDecoder(r.Body) - decoder.UseNumber() - - if err := decoder.Decode(stub); err != nil { +func (h *ApiHandler) AddHandle(w http.ResponseWriter, r *http.Request) { + byt, err := io.ReadAll(r.Body) + if err != nil { h.responseError(err, w) return } defer r.Body.Close() - if err := validateStub(stub); err != nil { + byt = bytes.TrimSpace(byt) + + if byt[0] == '{' && byt[len(byt)-1] == '}' { + byt = []byte("[" + string(byt) + "]") + } + + var stubs []*storage.Stub + decoder := json.NewDecoder(bytes.NewReader(byt)) + decoder.UseNumber() + + if err := decoder.Decode(&stubs); err != nil { h.responseError(err, w) return } + for _, stub := range stubs { + if err := validateStub(stub); err != nil { + h.responseError(err, w) + return + } + } + w.Header().Set("Content-Type", "application/json") - err := json.NewEncoder(w).Encode(h.stubs.Add(stub)) - if err != nil { + if err := json.NewEncoder(w).Encode(h.stubs.Add(stubs...)); err != nil { h.responseError(err, w) return } @@ -110,7 +123,9 @@ func (h *ApiHandler) addHandle(w http.ResponseWriter, r *http.Request) { func (h *ApiHandler) responseError(err error, w http.ResponseWriter) { w.WriteHeader(500) - _, _ = w.Write([]byte(err.Error())) + _ = json.NewEncoder(w).Encode(map[string]string{ + "error": err.Error(), + }) } func (h *ApiHandler) readStubs(path string) { diff --git a/stub/api_test.go b/stub/api_test.go new file mode 100644 index 00000000..9e1e19c4 --- /dev/null +++ b/stub/api_test.go @@ -0,0 +1,375 @@ +package stub_test + +import ( + "bytes" + "io" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/tokopedia/gripmock/stub" +) + +func TestStub(t *testing.T) { + type test struct { + name string + mock func() *http.Request + handler http.HandlerFunc + expect string + } + + api := stub.NewApiHandler() + + cases := []test{ + { + name: "add simple stub", + mock: func() *http.Request { + payload := `{ + "id": "43739ed8-2810-4f57-889b-4d3ff5795bce", + "service": "Testing", + "method":"TestMethod", + "input":{ + "equals":{ + "Hola":"Mundo" + } + }, + "output":{ + "data":{ + "Hello":"World" + } + } + }` + read := bytes.NewReader([]byte(payload)) + return httptest.NewRequest("POST", "/add", read) + }, + handler: api.AddHandle, + expect: `["43739ed8-2810-4f57-889b-4d3ff5795bce"]`, + }, + { + name: "list stub", + mock: func() *http.Request { + return httptest.NewRequest("GET", "/", nil) + }, + handler: api.ListHandle, + expect: "[{\"id\":\"43739ed8-2810-4f57-889b-4d3ff5795bce\",\"service\":\"Testing\",\"method\":\"TestMethod\",\"input\":{\"equals\":{\"Hola\":\"Mundo\"},\"contains\":null,\"matches\":null},\"output\":{\"data\":{\"Hello\":\"World\"},\"error\":\"\"}}]", + }, + { + name: "find stub equals", + mock: func() *http.Request { + payload := `{"service":"Testing","method":"TestMethod","data":{"Hola":"Mundo"}}` + return httptest.NewRequest("POST", "/find", bytes.NewReader([]byte(payload))) + }, + handler: api.SearchHandle, + expect: "{\"data\":{\"Hello\":\"World\"},\"error\":\"\"}\n", + }, + { + name: "add nested stub equals", + mock: func() *http.Request { + payload := `{ + "id": "b7211be4-06f7-4a2c-8453-359f077bcdb8", + "service": "NestedTesting", + "method":"TestMethod", + "input":{ + "equals":{ + "name": "Afra Gokce", + "age": 1, + "girl": true, + "null": null, + "greetings": { + "hola": "mundo", + "merhaba": "dunya" + }, + "cities": ["Istanbul", "Jakarta"] + } + }, + "output":{ + "data":{ + "Hello":"World" + } + } + }` + read := bytes.NewReader([]byte(payload)) + return httptest.NewRequest("POST", "/add", read) + }, + handler: api.AddHandle, + expect: `["b7211be4-06f7-4a2c-8453-359f077bcdb8"]`, + }, + { + name: "find nested stub equals", + mock: func() *http.Request { + payload := `{"service":"NestedTesting","method":"TestMethod","data":{"name":"Afra Gokce","age":1,"girl":true,"null":null,"greetings":{"hola":"mundo","merhaba":"dunya"},"cities":["Istanbul","Jakarta"]}}` + return httptest.NewRequest("POST", "/find", bytes.NewReader([]byte(payload))) + }, + handler: api.SearchHandle, + expect: "{\"data\":{\"Hello\":\"World\"},\"error\":\"\"}\n", + }, + { + name: "add stub contains", + mock: func() *http.Request { + payload := `{ + "id": "b5e35447-45bb-4b71-8ab4-41ba5dda669c", + "service": "Testing", + "method":"TestMethod", + "input":{ + "contains":{ + "field1":"hello field1", + "field3":"hello field3" + } + }, + "output":{ + "data":{ + "hello":"world" + } + } + }` + return httptest.NewRequest("POST", "/add", bytes.NewReader([]byte(payload))) + }, + handler: api.AddHandle, + expect: `["b5e35447-45bb-4b71-8ab4-41ba5dda669c"]`, + }, + { + name: "find stub contains", + mock: func() *http.Request { + payload := `{ + "service":"Testing", + "method":"TestMethod", + "data":{ + "field1":"hello field1", + "field2":"hello field2", + "field3":"hello field3" + } + }` + return httptest.NewRequest("GET", "/find", bytes.NewReader([]byte(payload))) + }, + handler: api.SearchHandle, + expect: "{\"data\":{\"hello\":\"world\"},\"error\":\"\"}\n", + }, + { + name: "add nested stub contains", + mock: func() *http.Request { + payload := `{ + "id": "b8e354d9-a211-49c7-9947-b617e1689e0f", + "service": "NestedTesting", + "method":"TestMethod", + "input":{ + "contains":{ + "key": "value", + "greetings": { + "hola": "mundo", + "merhaba": "dunya" + }, + "cities": ["Istanbul", "Jakarta"] + } + }, + "output":{ + "data":{ + "hello":"world" + } + } + }` + return httptest.NewRequest("POST", "/add", bytes.NewReader([]byte(payload))) + }, + handler: api.AddHandle, + expect: `["b8e354d9-a211-49c7-9947-b617e1689e0f"]`, + }, + { + name: "add multi stub contains", + mock: func() *http.Request { + payload := `[{ + "id": "3f68f410-bb58-49ad-b679-23f2ed690c1d", + "service": "NestedTesting", + "method":"TestMethod", + "input":{ + "equals":{ + "key": "stab1", + "greetings": { + "hola": "mundo", + "merhaba": "dunya" + }, + "cities": ["Istanbul", "Jakarta"] + } + }, + "output":{ + "data":{ + "hello":"world" + } + } + },{ + "id": "6da11d72-c0db-4075-9e72-31d61ffd0483", + "service": "NestedTesting", + "method":"TestMethod", + "input":{ + "equals":{ + "key": "stab2", + "greetings": { + "hola": "mundo", + "merhaba": "dunya" + }, + "cities": ["Istanbul", "Jakarta"] + } + }, + "output":{ + "data":{ + "hello":"world" + } + } + }]` + return httptest.NewRequest("POST", "/add", bytes.NewReader([]byte(payload))) + }, + handler: api.AddHandle, + expect: `["3f68f410-bb58-49ad-b679-23f2ed690c1d","6da11d72-c0db-4075-9e72-31d61ffd0483"]`, + }, + { + name: "find nested stub contains", + mock: func() *http.Request { + payload := `{ + "service":"NestedTesting", + "method":"TestMethod", + "data":{ + "key": "value", + "anotherKey": "anotherValue", + "greetings": { + "hola": "mundo", + "merhaba": "dunya", + "hello": "world" + }, + "cities": ["Istanbul", "Jakarta", "Winterfell"] + } + }` + return httptest.NewRequest("GET", "/find", bytes.NewReader([]byte(payload))) + }, + handler: api.SearchHandle, + expect: "{\"data\":{\"hello\":\"world\"},\"error\":\"\"}\n", + }, + { + name: "add stub matches regex", + mock: func() *http.Request { + payload := `{ + "id": "faf39edb-c695-493f-a25e-ecfc171977dc", + "service":"Testing2", + "method":"TestMethod", + "input":{ + "matches":{ + "field1":".*ello$" + } + }, + "output":{ + "data":{ + "reply":"OK" + } + } + }` + return httptest.NewRequest("POST", "/add", bytes.NewReader([]byte(payload))) + }, + handler: api.AddHandle, + expect: `["faf39edb-c695-493f-a25e-ecfc171977dc"]`, + }, + { + name: "find stub matches regex", + mock: func() *http.Request { + payload := `{ + "service":"Testing2", + "method":"TestMethod", + "data":{ + "field1":"hello" + } + }` + return httptest.NewRequest("GET", "/find", bytes.NewReader([]byte(payload))) + }, + handler: api.SearchHandle, + expect: "{\"data\":{\"reply\":\"OK\"},\"error\":\"\"}\n", + }, + { + name: "add nested stub matches regex", + mock: func() *http.Request { + payload := `{ + "id": "b1299ce3-a2a6-4fe7-94d4-0b68fc80afaa", + "service":"NestedTesting2", + "method":"TestMethod", + "input":{ + "matches":{ + "key": "[a-z]{3}ue", + "greetings": { + "hola": 1, + "merhaba": true, + "hello": "^he[l]{2,}o$" + }, + "cities": ["Istanbul", "Jakarta", ".*"], + "mixed": [5.5, false, ".*"] + } + }, + "output":{ + "data":{ + "reply":"OK" + } + } + }` + return httptest.NewRequest("POST", "/add", bytes.NewReader([]byte(payload))) + }, + handler: api.AddHandle, + expect: `["b1299ce3-a2a6-4fe7-94d4-0b68fc80afaa"]`, + }, + { + name: "find nested stub matches regex", + mock: func() *http.Request { + payload := `{ + "service":"NestedTesting2", + "method":"TestMethod", + "data":{ + "key": "value", + "greetings": { + "hola": 1, + "merhaba": true, + "hello": "helllllo" + }, + "cities": ["Istanbul", "Jakarta", "Gotham"], + "mixed": [5.5, false, "Gotham"] + } + } + }` + return httptest.NewRequest("GET", "/find", bytes.NewReader([]byte(payload))) + }, + handler: api.SearchHandle, + expect: "{\"data\":{\"reply\":\"OK\"},\"error\":\"\"}\n", + }, + { + name: "error find stub contains", + mock: func() *http.Request { + payload := `{ + "service":"Testing", + "method":"TestMethod", + "data":{ + "field1":"hello field1" + } + }` + return httptest.NewRequest("GET", "/find", bytes.NewReader([]byte(payload))) + }, + handler: api.SearchHandle, + expect: "{\"error\":\"Can't find stub \\n\\nService: Testing \\n\\nMethod: TestMethod \\n\\nInput\\n\\n{\\n\\t\\\"field1\\\": \\\"hello field1\\\"\\n}\\n\\nClosest Match \\n\\ncontains:{\\n\\t\\\"field1\\\": \\\"hello field1\\\",\\n\\t\\\"field3\\\": \\\"hello field3\\\"\\n}\"}", + }, + { + name: "error find stub equals", + mock: func() *http.Request { + payload := `{"service":"Testing","method":"TestMethod","data":{"Hola":"Dunia"}}` + return httptest.NewRequest("POST", "/find", bytes.NewReader([]byte(payload))) + }, + handler: api.SearchHandle, + expect: "{\"error\":\"Can't find stub \\n\\nService: Testing \\n\\nMethod: TestMethod \\n\\nInput\\n\\n{\\n\\t\\\"Hola\\\": \\\"Dunia\\\"\\n}\\n\\nClosest Match \\n\\nequals:{\\n\\t\\\"Hola\\\": \\\"Mundo\\\"\\n}\"}", + }, + } + + for _, v := range cases { + t.Run(v.name, func(t *testing.T) { + wrt := httptest.NewRecorder() + req := v.mock() + v.handler(wrt, req) + res, err := io.ReadAll(wrt.Result().Body) + + assert.NoError(t, err) + require.JSONEq(t, v.expect, string(res), string(res)) + }) + } +} diff --git a/stub/stub.go b/stub/stub.go index 7bf60383..10b6335e 100644 --- a/stub/stub.go +++ b/stub/stub.go @@ -37,10 +37,10 @@ func RunStubServer(opt Options) { router.Handle("/health", healthcheck).Methods("GET") apiRouter := router.PathPrefix("/api").Subrouter() - apiRouter.HandleFunc("/stubs/search", api.searchHandle).Methods("POST") - apiRouter.HandleFunc("/stubs", api.listHandle).Methods("GET") - apiRouter.HandleFunc("/stubs", api.addHandle).Methods("POST") - apiRouter.HandleFunc("/stubs", api.purgeHandle).Methods("DELETE") + apiRouter.HandleFunc("/stubs/search", api.SearchHandle).Methods("POST") + apiRouter.HandleFunc("/stubs", api.ListHandle).Methods("GET") + apiRouter.HandleFunc("/stubs", api.AddHandle).Methods("POST") + apiRouter.HandleFunc("/stubs", api.PurgeHandle).Methods("DELETE") fmt.Println("Serving stub admin on http://" + addr) go func() { From 61d3b027e1c8045e8aacec731d60f74f1c7cba5e Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Fri, 1 Sep 2023 18:27:40 +0300 Subject: [PATCH 2/4] fix http code --- stub/actions.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/stub/actions.go b/stub/actions.go index 0b094417..56691bf7 100644 --- a/stub/actions.go +++ b/stub/actions.go @@ -60,7 +60,8 @@ func (h *ApiHandler) SearchHandle(w http.ResponseWriter, r *http.Request) { output, err := findStub(h.stubs, stub) if err != nil { log.Println(err) - h.responseError(err, w) + w.WriteHeader(404) + h.writeResponseError(err, w) return } @@ -123,6 +124,10 @@ func (h *ApiHandler) AddHandle(w http.ResponseWriter, r *http.Request) { func (h *ApiHandler) responseError(err error, w http.ResponseWriter) { w.WriteHeader(500) + h.writeResponseError(err, w) +} + +func (h *ApiHandler) writeResponseError(err error, w http.ResponseWriter) { _ = json.NewEncoder(w).Encode(map[string]string{ "error": err.Error(), }) From 4fff367479d6ea983a7d71a59bd0d8f23d1f7588 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Fri, 1 Sep 2023 20:10:45 +0300 Subject: [PATCH 3/4] mini refactoring --- stub/storage.go | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/stub/storage.go b/stub/storage.go index 33a35e6b..501dea7e 100644 --- a/stub/storage.go +++ b/stub/storage.go @@ -154,31 +154,24 @@ func matches(expect, actual map[string]interface{}) bool { } func find(expect, actual interface{}, acc, exactMatch bool, f matchFunc) bool { - // circuit brake if !acc { return false } - expectArrayValue, expectArrayOk := expect.([]interface{}) - if expectArrayOk { + if expectArrayValue, expectArrayOk := expect.([]interface{}); expectArrayOk { actualArrayValue, actualArrayOk := actual.([]interface{}) if !actualArrayOk { - acc = false - return acc + return false } if exactMatch { if len(expectArrayValue) != len(actualArrayValue) { - acc = false - return acc - } - } else { - if len(expectArrayValue) > len(actualArrayValue) { - acc = false - return acc + return false } + } else if len(expectArrayValue) > len(actualArrayValue) { + return false } for expectItemIndex, expectItemValue := range expectArrayValue { @@ -189,25 +182,18 @@ func find(expect, actual interface{}, acc, exactMatch bool, f matchFunc) bool { return acc } - expectMapValue, expectMapOk := expect.(map[string]interface{}) - if expectMapOk { - + if expectMapValue, expectMapOk := expect.(map[string]interface{}); expectMapOk { actualMapValue, actualMapOk := actual.(map[string]interface{}) if !actualMapOk { - acc = false - return acc + return false } if exactMatch { if len(expectMapValue) != len(actualMapValue) { - acc = false - return acc - } - } else { - if len(expectMapValue) > len(actualMapValue) { - acc = false - return acc + return false } + } else if len(expectMapValue) > len(actualMapValue) { + return false } for expectItemKey, expectItemValue := range expectMapValue { From 0a2de0ea46911e64625fea11228d84765a709794 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Fri, 1 Sep 2023 20:24:53 +0300 Subject: [PATCH 4/4] add unit --- stub/api_test.go | 53 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/stub/api_test.go b/stub/api_test.go index 9e1e19c4..f781e13d 100644 --- a/stub/api_test.go +++ b/stub/api_test.go @@ -43,7 +43,7 @@ func TestStub(t *testing.T) { } }` read := bytes.NewReader([]byte(payload)) - return httptest.NewRequest("POST", "/add", read) + return httptest.NewRequest("POST", "/api/stubs", read) }, handler: api.AddHandle, expect: `["43739ed8-2810-4f57-889b-4d3ff5795bce"]`, @@ -51,7 +51,7 @@ func TestStub(t *testing.T) { { name: "list stub", mock: func() *http.Request { - return httptest.NewRequest("GET", "/", nil) + return httptest.NewRequest("GET", "/api/stubs", nil) }, handler: api.ListHandle, expect: "[{\"id\":\"43739ed8-2810-4f57-889b-4d3ff5795bce\",\"service\":\"Testing\",\"method\":\"TestMethod\",\"input\":{\"equals\":{\"Hola\":\"Mundo\"},\"contains\":null,\"matches\":null},\"output\":{\"data\":{\"Hello\":\"World\"},\"error\":\"\"}}]", @@ -60,7 +60,7 @@ func TestStub(t *testing.T) { name: "find stub equals", mock: func() *http.Request { payload := `{"service":"Testing","method":"TestMethod","data":{"Hola":"Mundo"}}` - return httptest.NewRequest("POST", "/find", bytes.NewReader([]byte(payload))) + return httptest.NewRequest("POST", "/api/stubs/search", bytes.NewReader([]byte(payload))) }, handler: api.SearchHandle, expect: "{\"data\":{\"Hello\":\"World\"},\"error\":\"\"}\n", @@ -92,7 +92,7 @@ func TestStub(t *testing.T) { } }` read := bytes.NewReader([]byte(payload)) - return httptest.NewRequest("POST", "/add", read) + return httptest.NewRequest("POST", "/api/stubs", read) }, handler: api.AddHandle, expect: `["b7211be4-06f7-4a2c-8453-359f077bcdb8"]`, @@ -101,7 +101,7 @@ func TestStub(t *testing.T) { name: "find nested stub equals", mock: func() *http.Request { payload := `{"service":"NestedTesting","method":"TestMethod","data":{"name":"Afra Gokce","age":1,"girl":true,"null":null,"greetings":{"hola":"mundo","merhaba":"dunya"},"cities":["Istanbul","Jakarta"]}}` - return httptest.NewRequest("POST", "/find", bytes.NewReader([]byte(payload))) + return httptest.NewRequest("POST", "/api/stubs/search", bytes.NewReader([]byte(payload))) }, handler: api.SearchHandle, expect: "{\"data\":{\"Hello\":\"World\"},\"error\":\"\"}\n", @@ -125,7 +125,7 @@ func TestStub(t *testing.T) { } } }` - return httptest.NewRequest("POST", "/add", bytes.NewReader([]byte(payload))) + return httptest.NewRequest("POST", "/api/stubs", bytes.NewReader([]byte(payload))) }, handler: api.AddHandle, expect: `["b5e35447-45bb-4b71-8ab4-41ba5dda669c"]`, @@ -142,7 +142,7 @@ func TestStub(t *testing.T) { "field3":"hello field3" } }` - return httptest.NewRequest("GET", "/find", bytes.NewReader([]byte(payload))) + return httptest.NewRequest("GET", "/api/stubs/search", bytes.NewReader([]byte(payload))) }, handler: api.SearchHandle, expect: "{\"data\":{\"hello\":\"world\"},\"error\":\"\"}\n", @@ -170,7 +170,7 @@ func TestStub(t *testing.T) { } } }` - return httptest.NewRequest("POST", "/add", bytes.NewReader([]byte(payload))) + return httptest.NewRequest("POST", "/api/stubs", bytes.NewReader([]byte(payload))) }, handler: api.AddHandle, expect: `["b8e354d9-a211-49c7-9947-b617e1689e0f"]`, @@ -217,7 +217,7 @@ func TestStub(t *testing.T) { } } }]` - return httptest.NewRequest("POST", "/add", bytes.NewReader([]byte(payload))) + return httptest.NewRequest("POST", "/api/stubs", bytes.NewReader([]byte(payload))) }, handler: api.AddHandle, expect: `["3f68f410-bb58-49ad-b679-23f2ed690c1d","6da11d72-c0db-4075-9e72-31d61ffd0483"]`, @@ -239,7 +239,7 @@ func TestStub(t *testing.T) { "cities": ["Istanbul", "Jakarta", "Winterfell"] } }` - return httptest.NewRequest("GET", "/find", bytes.NewReader([]byte(payload))) + return httptest.NewRequest("GET", "/api/stubs/search", bytes.NewReader([]byte(payload))) }, handler: api.SearchHandle, expect: "{\"data\":{\"hello\":\"world\"},\"error\":\"\"}\n", @@ -262,7 +262,7 @@ func TestStub(t *testing.T) { } } }` - return httptest.NewRequest("POST", "/add", bytes.NewReader([]byte(payload))) + return httptest.NewRequest("POST", "/api/stubs", bytes.NewReader([]byte(payload))) }, handler: api.AddHandle, expect: `["faf39edb-c695-493f-a25e-ecfc171977dc"]`, @@ -277,7 +277,7 @@ func TestStub(t *testing.T) { "field1":"hello" } }` - return httptest.NewRequest("GET", "/find", bytes.NewReader([]byte(payload))) + return httptest.NewRequest("GET", "/api/stubs/search", bytes.NewReader([]byte(payload))) }, handler: api.SearchHandle, expect: "{\"data\":{\"reply\":\"OK\"},\"error\":\"\"}\n", @@ -307,7 +307,7 @@ func TestStub(t *testing.T) { } } }` - return httptest.NewRequest("POST", "/add", bytes.NewReader([]byte(payload))) + return httptest.NewRequest("POST", "/api/stubs", bytes.NewReader([]byte(payload))) }, handler: api.AddHandle, expect: `["b1299ce3-a2a6-4fe7-94d4-0b68fc80afaa"]`, @@ -330,7 +330,7 @@ func TestStub(t *testing.T) { } } }` - return httptest.NewRequest("GET", "/find", bytes.NewReader([]byte(payload))) + return httptest.NewRequest("GET", "/api/stubs/search", bytes.NewReader([]byte(payload))) }, handler: api.SearchHandle, expect: "{\"data\":{\"reply\":\"OK\"},\"error\":\"\"}\n", @@ -345,7 +345,7 @@ func TestStub(t *testing.T) { "field1":"hello field1" } }` - return httptest.NewRequest("GET", "/find", bytes.NewReader([]byte(payload))) + return httptest.NewRequest("GET", "/api/stubs/search", bytes.NewReader([]byte(payload))) }, handler: api.SearchHandle, expect: "{\"error\":\"Can't find stub \\n\\nService: Testing \\n\\nMethod: TestMethod \\n\\nInput\\n\\n{\\n\\t\\\"field1\\\": \\\"hello field1\\\"\\n}\\n\\nClosest Match \\n\\ncontains:{\\n\\t\\\"field1\\\": \\\"hello field1\\\",\\n\\t\\\"field3\\\": \\\"hello field3\\\"\\n}\"}", @@ -354,7 +354,7 @@ func TestStub(t *testing.T) { name: "error find stub equals", mock: func() *http.Request { payload := `{"service":"Testing","method":"TestMethod","data":{"Hola":"Dunia"}}` - return httptest.NewRequest("POST", "/find", bytes.NewReader([]byte(payload))) + return httptest.NewRequest("POST", "/api/stubs/search", bytes.NewReader([]byte(payload))) }, handler: api.SearchHandle, expect: "{\"error\":\"Can't find stub \\n\\nService: Testing \\n\\nMethod: TestMethod \\n\\nInput\\n\\n{\\n\\t\\\"Hola\\\": \\\"Dunia\\\"\\n}\\n\\nClosest Match \\n\\nequals:{\\n\\t\\\"Hola\\\": \\\"Mundo\\\"\\n}\"}", @@ -369,7 +369,26 @@ func TestStub(t *testing.T) { res, err := io.ReadAll(wrt.Result().Body) assert.NoError(t, err) - require.JSONEq(t, v.expect, string(res), string(res)) + require.JSONEq(t, v.expect, string(res)) }) } + + t.Run("purge handler", func(t *testing.T) { + deleteWrt := httptest.NewRecorder() + deleteReq := httptest.NewRequest("DELETE", "/api/stubs", nil) + + api.PurgeHandle(deleteWrt, deleteReq) + + listWrt := httptest.NewRecorder() + listReq := httptest.NewRequest("GET", "/api/stubs", nil) + + api.ListHandle(listWrt, listReq) + + res, err := io.ReadAll(listWrt.Result().Body) + + assert.NoError(t, err) + require.Equal(t, http.StatusNoContent, deleteWrt.Result().StatusCode) + + require.JSONEq(t, "[]", string(res)) + }) }