Skip to content

Commit 3ce9e37

Browse files
committed
fix: add mutex to avoid race conditions on time count + support body matcher for url encoded form
1 parent 9a59c6b commit 3ce9e37

File tree

7 files changed

+66
-18
lines changed

7 files changed

+66
-18
lines changed

server/handlers/mocks.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"math/rand"
66
"net/http"
7+
"sync"
78
"time"
89

910
"github.com/Thiht/smocker/server/services"
@@ -16,15 +17,20 @@ import (
1617

1718
type Mocks struct {
1819
mocksServices services.Mocks
20+
mu sync.Mutex
1921
}
2022

2123
func NewMocks(ms services.Mocks) *Mocks {
2224
return &Mocks{
2325
mocksServices: ms,
26+
mu: sync.Mutex{},
2427
}
2528
}
2629

2730
func (m *Mocks) GenericHandler(c echo.Context) error {
31+
m.mu.Lock()
32+
defer m.mu.Unlock()
33+
2834
actualRequest := types.HTTPRequestToRequest(c.Request())
2935
b, _ := yaml.Marshal(actualRequest)
3036
log.Debugf("Received request:\n---\n%s\n", string(b))

server/types/history.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package types
33
import (
44
"bytes"
55
"encoding/json"
6-
"io/ioutil"
6+
"io"
77
"net"
88
"net/http"
99
"net/url"
@@ -55,12 +55,12 @@ func HTTPRequestToRequest(req *http.Request) Request {
5555
bodyBytes := []byte{}
5656
if req.Body != nil {
5757
var err error
58-
bodyBytes, err = ioutil.ReadAll(req.Body)
58+
bodyBytes, err = io.ReadAll(req.Body)
5959
if err != nil {
6060
log.WithError(err).Error("Failed to read request body")
6161
}
6262
}
63-
req.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
63+
req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
6464
var body interface{}
6565
var tmp map[string]interface{}
6666
if err := json.Unmarshal(bodyBytes, &tmp); err != nil {

server/types/matchers.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package types
33
import (
44
"encoding/json"
55
"fmt"
6+
"net/http"
7+
"net/url"
68
"regexp"
79

810
log "github.com/sirupsen/logrus"
@@ -252,11 +254,22 @@ type BodyMatcher struct {
252254
bodyJson map[string]StringMatcher
253255
}
254256

255-
func (bm BodyMatcher) Match(value string) bool {
257+
func (bm BodyMatcher) Match(headers http.Header, value string) bool {
256258
if bm.bodyString != nil {
257259
return bm.bodyString.Match(value)
258260
}
259261

262+
if headers.Get("Content-Type") == "application/x-www-form-urlencoded" {
263+
m, err := url.ParseQuery(value)
264+
if err != nil {
265+
log.WithError(err).Error("Failed to read request body as encoded form")
266+
} else if b, err := json.Marshal(m); err != nil {
267+
log.WithError(err).Error("Failed to serialize form body as JSON")
268+
} else {
269+
value = string(b)
270+
}
271+
}
272+
260273
j, err := objx.FromJSON(value)
261274
if err != nil {
262275
return false

server/types/mock.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ func (mr MockRequest) Match(req Request) bool {
126126
log.Trace("Query params did not match")
127127
return false
128128
}
129-
matchBody := mr.Body == nil || mr.Body.Match(req.BodyString)
129+
matchBody := mr.Body == nil || mr.Body.Match(req.Headers, req.BodyString)
130130
if !matchBody {
131131
log.Trace("Body did not match")
132132
return false

tests/data/matcher_mock_list.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,12 @@
8686
response:
8787
body: >
8888
{"message": "test11"}
89+
- request:
90+
path: /test12
91+
headers:
92+
Content-Type: application/x-www-form-urlencoded
93+
body:
94+
key1[0]: test
95+
response:
96+
body: >
97+
{"message": "test13"}

tests/features/set_mocks.yml

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -105,19 +105,20 @@ testcases:
105105
url: http://localhost:8081/mocks
106106
assertions:
107107
- result.statuscode ShouldEqual 200
108-
- result.bodyjson.__len__ ShouldEqual 8
109-
- result.bodyjson.bodyjson7.request.path.matcher ShouldEqual "ShouldMatch"
110-
- result.bodyjson.bodyjson7.request.path.value ShouldEqual "/.*"
111-
- result.bodyjson.bodyjson6.request.method.matcher ShouldEqual "ShouldContainSubstring"
112-
- result.bodyjson.bodyjson6.request.method.value ShouldEqual "PO"
113-
- result.bodyjson.bodyjson5.request.body.matcher ShouldEqual "ShouldEqualJSON"
114-
- result.bodyjson.bodyjson5.request.body.value ShouldContainSubstring id
115-
- result.bodyjson.bodyjson4.request.headers.content-type.content-type0.matcher ShouldEqual "ShouldMatch"
116-
- result.bodyjson.bodyjson4.request.headers.content-type.content-type0.value ShouldEqual application/.*
117-
- result.bodyjson.bodyjson3.request.query_params.test.test0.value ShouldEqual true
118-
- result.bodyjson.bodyjson2.request.body.matcher ShouldEqual "ShouldNotBeEmpty"
119-
- result.bodyjson.bodyjson1.request.query_params.test.test0.value ShouldEqual true
120-
- result.bodyjson.bodyjson0.request.body.key1.value ShouldEqual test
108+
- result.bodyjson.__len__ ShouldEqual 9
109+
- result.bodyjson.bodyjson8.request.path.matcher ShouldEqual "ShouldMatch"
110+
- result.bodyjson.bodyjson8.request.path.value ShouldEqual "/.*"
111+
- result.bodyjson.bodyjson7.request.method.matcher ShouldEqual "ShouldContainSubstring"
112+
- result.bodyjson.bodyjson7.request.method.value ShouldEqual "PO"
113+
- result.bodyjson.bodyjson6.request.body.matcher ShouldEqual "ShouldEqualJSON"
114+
- result.bodyjson.bodyjson6.request.body.value ShouldContainSubstring id
115+
- result.bodyjson.bodyjson5.request.headers.content-type.content-type0.matcher ShouldEqual "ShouldMatch"
116+
- result.bodyjson.bodyjson5.request.headers.content-type.content-type0.value ShouldEqual application/.*
117+
- result.bodyjson.bodyjson4.request.query_params.test.test0.value ShouldEqual true
118+
- result.bodyjson.bodyjson3.request.body.matcher ShouldEqual "ShouldNotBeEmpty"
119+
- result.bodyjson.bodyjson2.request.query_params.test.test0.value ShouldEqual true
120+
- result.bodyjson.bodyjson1.request.body.key1.value ShouldEqual test
121+
- result.bodyjson.bodyjson0.request.body.key1[0].value ShouldEqual test
121122

122123
- name: Add dynamic mocks
123124
steps:

tests/features/use_mocks.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,25 @@ testcases:
166166
assertions:
167167
- result.statuscode ShouldEqual 666
168168

169+
- type: http
170+
method: POST
171+
url: http://localhost:8080/test12
172+
headers:
173+
Content-Type: application/x-www-form-urlencoded
174+
body: key1=test
175+
assertions:
176+
- result.statuscode ShouldEqual 200
177+
- result.bodyjson.message ShouldEqual test13
178+
179+
- type: http
180+
method: POST
181+
url: http://localhost:8080/test12
182+
headers:
183+
Content-Type: application/x-www-form-urlencoded
184+
body: key1=test2
185+
assertions:
186+
- result.statuscode ShouldEqual 666
187+
169188
- name: Use dynamic mock list
170189
steps:
171190
- type: http

0 commit comments

Comments
 (0)