Skip to content

Commit

Permalink
Merge pull request #5 from prongbang/feature/multi-case
Browse files Browse the repository at this point in the history
Feature/multi case
  • Loading branch information
prongbang committed Aug 21, 2020
2 parents e0e3b74 + b661944 commit 0608096
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 26 deletions.
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,45 @@ routes:
body: >
{"message": "success"}
```

### User with multiple case

```yaml
routes:
users:
request:
method: "POST"
url: "/api/v1/user"
header:
Api-Key: "ABC"
cases:
user_history:
body:
action: "transaction"
response:
status: 200
body_file: user-history.json
user_check_consent:
body:
action: "consent"
accept: ""
response:
status: 200
body_file: user-check-consent.json
user_accept_consent:
body:
action: "consent"
accept: "Y"
response:
status: 200
body_file: user-accept-consent.json
get_profile:
body:
username: "*"
userId: "*"
response:
status: 200
body_file: profile-self.json
```

```*``` - field required.
14 changes: 14 additions & 0 deletions pkg/api/core/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,17 @@ func BindBody(mockBody map[string]interface{}, r *http.Request) map[string]inter
}
return data
}

func BindParameter(mockBody map[string]interface{}, r *http.Request) map[string]interface{} {
data := map[string]interface{}{}
for k := range mockBody {
v := r.PostFormValue(k)
if v != "" {
data[k] = v
}
}
if len(data) == 0 {
_ = json.NewDecoder(r.Body).Decode(&data)
}
return data
}
61 changes: 47 additions & 14 deletions pkg/api/wiremock/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,56 @@ func (h *handler) Handle(w http.ResponseWriter, r *http.Request) {
header := core.BindHeader(h.Routers.Request.Header, r)
body := core.BindBody(h.Routers.Request.Body, r)

// Process parameter matching
matching := h.UseCase.ParameterMatching(Parameters{
HttpReqHeader: header,
MockReqHeader: h.Routers.Request.Header,
HttpReqBody: body,
MockReqBody: h.Routers.Request.Body,
})

// Prepared response
w.Header().Set("Content-Type", "application/json")
if matching.IsMatch {
w.WriteHeader(h.Routers.Response.Status)
response := h.UseCase.GetMockResponse(h.Routers.Response)
_, _ = w.Write(response)

// Process cases matching
if len(h.Routers.Request.Cases) > 0 {

// Process cases matching
matching := h.UseCase.CasesMatching(h.Routers.Response.FileName, h.Routers.Request.Cases, Parameters{
ReqHeader: ReqHeader{
Http: header,
Mock: h.Routers.Request.Header,
},
ReqBody: ReqBody{
Http: body,
},
})

// Process response
if matching.IsMatch {
w.WriteHeader(matching.Case.Response.Status)
response := h.UseCase.GetMockResponse(matching.Case.Response)
_, _ = w.Write(response)
} else {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write(matching.Result)
}

} else {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write(matching.Result)

// Process parameter matching
matching := h.UseCase.ParameterMatching(Parameters{
ReqHeader: ReqHeader{
Http: header,
Mock: h.Routers.Request.Header,
},
ReqBody: ReqBody{
Http: body,
Mock: h.Routers.Request.Body,
},
})

// Prepared response
if matching.IsMatch {
w.WriteHeader(h.Routers.Response.Status)
response := h.UseCase.GetMockResponse(h.Routers.Response)
_, _ = w.Write(response)
} else {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write(matching.Result)
}
}
}

Expand Down
28 changes: 24 additions & 4 deletions pkg/api/wiremock/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Request struct {
URL string `yaml:"url"`
Header map[string]interface{} `yaml:"header"`
Body map[string]interface{} `yaml:"body"`
Cases map[string]Cases `yaml:"cases"`
}

type Response struct {
Expand All @@ -28,9 +29,28 @@ type Matching struct {
IsMatch bool
}

type CaseMatching struct {
Result []byte
IsMatch bool
Case Cases
}

type ReqHeader struct {
Http map[string]interface{}
Mock map[string]interface{}
}

type ReqBody struct {
Http map[string]interface{}
Mock map[string]interface{}
}

type Parameters struct {
HttpReqHeader map[string]interface{}
MockReqHeader map[string]interface{}
HttpReqBody map[string]interface{}
MockReqBody map[string]interface{}
ReqHeader ReqHeader
ReqBody ReqBody
}

type Cases struct {
Body map[string]interface{} `yaml:"body"`
Response Response `yaml:"response"`
}
84 changes: 76 additions & 8 deletions pkg/api/wiremock/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
)

type UseCase interface {
CasesMatching(path string, cases map[string]Cases, params Parameters) CaseMatching
ParameterMatching(params Parameters) Matching
GetMockResponse(resp Response) []byte
ReadSourceRouteYml(routeName string) []byte
Expand All @@ -18,33 +19,100 @@ type UseCase interface {
type useCase struct {
}

func (u *useCase) CasesMatching(path string, cases map[string]Cases, params Parameters) CaseMatching {
// Process header matching
require := map[string]interface{}{}
errors := map[string]interface{}{}
matchingHeader := 0
for k, v := range params.ReqBody.Mock {
vs := fmt.Sprintf("%v", v)
ks := fmt.Sprintf("%v", params.ReqHeader.Http[k])
if vs == ks {
matchingHeader = matchingHeader + 1
continue
}
if params.ReqHeader.Http[k] == nil {
errors[k] = "Require header " + k
} else {
errors[k] = "The header " + k + " not match"
}
}
if len(errors) > 0 {
require["errors"] = errors
}
require["message"] = "validation error"
require["status"] = "error"
result, err := json.Marshal(require)
if err != nil {
result = []byte("{}")
}
matchingHeaderRequest := len(params.ReqBody.Mock) == matchingHeader

// Process body matching
matchingBodyRequest := false
var foundCase Cases
for _, vMock := range cases {
matchingBody := 0
vMock.Response.FileName = path
for ck, cv := range vMock.Body {
vs := fmt.Sprintf("%v", cv)
ks := fmt.Sprintf("%v", params.ReqBody.Http[ck])

// Check require field value is not empty
if vs == "*" {
if params.ReqBody.Http[ck] != nil {
matchingBody = matchingBody + 1
}
}

// Value matching
if vs == ks {
matchingBody = matchingBody + 1
}
}

// Contains value
matchingBodyRequest = len(vMock.Body) == matchingBody
if matchingBodyRequest {
foundCase = vMock
break
}
}

return CaseMatching{
IsMatch: matchingBodyRequest && matchingHeaderRequest,
Result: result,
Case: foundCase,
}
}

func (u *useCase) ParameterMatching(params Parameters) Matching {
require := map[string]interface{}{}
errors := map[string]interface{}{}
matchingHeader := 0
matchingBody := 0
for k, v := range params.MockReqBody {
for k, v := range params.ReqBody.Mock {
vs := fmt.Sprintf("%v", v)
ks := fmt.Sprintf("%v", params.HttpReqBody[k])
ks := fmt.Sprintf("%v", params.ReqBody.Http[k])
if vs == ks {
matchingBody = matchingBody + 1
continue
}
if params.HttpReqBody[k] == nil {
if params.ReqBody.Http[k] == nil {
errors[k] = "Require " + k
} else {
errors[k] = "The " + k + " not match"
}
}

for k, v := range params.MockReqHeader {
for k, v := range params.ReqHeader.Mock {
vs := fmt.Sprintf("%v", v)
ks := fmt.Sprintf("%v", params.HttpReqHeader[k])
ks := fmt.Sprintf("%v", params.ReqHeader.Http[k])
if vs == ks {
matchingHeader = matchingHeader + 1
continue
}
if params.HttpReqHeader[k] == nil {
if params.ReqHeader.Http[k] == nil {
errors[k] = "Require header " + k
} else {
errors[k] = "The header " + k + " not match"
Expand All @@ -62,8 +130,8 @@ func (u *useCase) ParameterMatching(params Parameters) Matching {
result = []byte("{}")
}

isMatchHeader := len(params.MockReqHeader) == matchingHeader
isMatchBody := len(params.MockReqBody) == matchingBody
isMatchHeader := len(params.ReqHeader.Mock) == matchingHeader
isMatchBody := len(params.ReqBody.Mock) == matchingBody

return Matching{
Result: result,
Expand Down

0 comments on commit 0608096

Please sign in to comment.