Skip to content

Commit af07491

Browse files
authored
Support for wiremock 3.0.0 features (#32)
* Add logical not * Add MatchesJsonSchema * Add Path templates
1 parent 21343b1 commit af07491

11 files changed

+188
-28
lines changed

client_test.go

+43-17
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,7 @@ func TestStubRule_ToJson(t *testing.T) {
8383
WithScheme("http").
8484
WithPort(8080).
8585
WithBearerToken(StartsWith("token")).
86-
WillReturnResponse(
87-
NewResponse().
88-
WithStatus(http.StatusOK),
89-
),
86+
WillReturnResponse(OK()),
9087
ExpectedFileName: "expected-template-bearer-auth-startsWith.json",
9188
},
9289
{
@@ -96,10 +93,7 @@ func TestStubRule_ToJson(t *testing.T) {
9693
WithScheme("http").
9794
WithPort(8080).
9895
WithBearerToken(EqualTo("token")).
99-
WillReturnResponse(
100-
NewResponse().
101-
WithStatus(http.StatusOK),
102-
),
96+
WillReturnResponse(OK()),
10397
ExpectedFileName: "expected-template-bearer-auth-equalTo.json",
10498
},
10599
{
@@ -109,10 +103,7 @@ func TestStubRule_ToJson(t *testing.T) {
109103
WithScheme("http").
110104
WithPort(8080).
111105
WithBearerToken(Contains("token")).
112-
WillReturnResponse(
113-
NewResponse().
114-
WithStatus(http.StatusOK),
115-
),
106+
WillReturnResponse(OK()),
116107
ExpectedFileName: "expected-template-bearer-auth-contains.json",
117108
},
118109
{
@@ -122,12 +113,47 @@ func TestStubRule_ToJson(t *testing.T) {
122113
WithScheme("http").
123114
WithPort(8080).
124115
WithBearerToken(EqualTo("token123").And(StartsWith("token"))).
125-
WillReturnResponse(
126-
NewResponse().
127-
WithStatus(http.StatusOK),
128-
),
116+
WillReturnResponse(OK()),
129117
ExpectedFileName: "expected-template-bearer-auth-logicalMatcher.json",
130118
},
119+
{
120+
Name: "NotLogicalMatcher",
121+
StubRule: Post(URLPathEqualTo("/example")).
122+
WithQueryParam("firstName", Not(EqualTo("John").Or(EqualTo("Jack")))).
123+
WillReturnResponse(OK()),
124+
ExpectedFileName: "not-logical-expression.json",
125+
},
126+
{
127+
Name: "JsonSchemaMatcher",
128+
StubRule: Post(URLPathEqualTo("/example")).
129+
WithQueryParam("firstName", MatchesJsonSchema(
130+
`{
131+
"type": "object",
132+
"required": [
133+
"name"
134+
],
135+
"properties": {
136+
"name": {
137+
"type": "string"
138+
},
139+
"tag": {
140+
"type": "string"
141+
}
142+
}
143+
}`,
144+
"V202012",
145+
)).
146+
WillReturnResponse(OK()),
147+
ExpectedFileName: "matches-Json-schema.json",
148+
},
149+
{
150+
Name: "URLPathTemplateMatcher",
151+
StubRule: Get(URLPathTemplate("/contacts/{contactId}/addresses/{addressId}")).
152+
WithPathParam("contactId", EqualTo("12345")).
153+
WithPathParam("addressId", EqualTo("99876")).
154+
WillReturnResponse(OK()),
155+
ExpectedFileName: "url-path-templating.json",
156+
},
131157
}
132158

133159
for _, tc := range testCases {
@@ -142,7 +168,7 @@ func TestStubRule_ToJson(t *testing.T) {
142168
var expected map[string]interface{}
143169
err = json.Unmarshal([]byte(fmt.Sprintf(string(rawExpectedRequestBody), stubRule.uuid, stubRule.uuid)), &expected)
144170
if err != nil {
145-
t.Fatalf("StubRole json.Unmarshal error: %v", err)
171+
t.Fatalf("StubRule json.Unmarshal error: %v", err)
146172
}
147173

148174
rawResult, err := json.Marshal(stubRule)

logical_matcher.go

+14
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ func (m LogicalMatcher) MarshalJSON() ([]byte, error) {
1616

1717
// ParseMatcher returns the map representation of the structure.
1818
func (m LogicalMatcher) ParseMatcher() map[string]interface{} {
19+
if m.operator == "not" {
20+
return map[string]interface{}{
21+
m.operator: m.operands[0],
22+
}
23+
}
24+
1925
return map[string]interface{}{
2026
m.operator: m.operands,
2127
}
@@ -56,3 +62,11 @@ func And(matchers ...BasicParamMatcher) LogicalMatcher {
5662
operands: matchers,
5763
}
5864
}
65+
66+
// Not returns a logical NOT of the given matcher. Required wiremock version >= 3.0.0
67+
func Not(matcher BasicParamMatcher) LogicalMatcher {
68+
return LogicalMatcher{
69+
operator: "not",
70+
operands: []BasicParamMatcher{matcher},
71+
}
72+
}

matching.go

+12-10
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@ package wiremock
22

33
// Types of params matching.
44
const (
5-
ParamEqualTo ParamMatchingStrategy = "equalTo"
6-
ParamMatches ParamMatchingStrategy = "matches"
7-
ParamContains ParamMatchingStrategy = "contains"
8-
ParamEqualToXml ParamMatchingStrategy = "equalToXml"
9-
ParamEqualToJson ParamMatchingStrategy = "equalToJson"
10-
ParamMatchesXPath ParamMatchingStrategy = "matchesXPath"
11-
ParamMatchesJsonPath ParamMatchingStrategy = "matchesJsonPath"
12-
ParamAbsent ParamMatchingStrategy = "absent"
13-
ParamDoesNotMatch ParamMatchingStrategy = "doesNotMatch"
14-
ParamDoesNotContains ParamMatchingStrategy = "doesNotContain"
5+
ParamEqualTo ParamMatchingStrategy = "equalTo"
6+
ParamMatches ParamMatchingStrategy = "matches"
7+
ParamContains ParamMatchingStrategy = "contains"
8+
ParamEqualToXml ParamMatchingStrategy = "equalToXml"
9+
ParamEqualToJson ParamMatchingStrategy = "equalToJson"
10+
ParamMatchesXPath ParamMatchingStrategy = "matchesXPath"
11+
ParamMatchesJsonPath ParamMatchingStrategy = "matchesJsonPath"
12+
ParamAbsent ParamMatchingStrategy = "absent"
13+
ParamDoesNotMatch ParamMatchingStrategy = "doesNotMatch"
14+
ParamDoesNotContains ParamMatchingStrategy = "doesNotContain"
15+
ParamMatchesJsonSchema ParamMatchingStrategy = "matchesJsonSchema"
1516
)
1617

1718
// Types of url matching.
@@ -20,6 +21,7 @@ const (
2021
URLPathEqualToRule URLMatchingStrategy = "urlPath"
2122
URLPathMatchingRule URLMatchingStrategy = "urlPathPattern"
2223
URLMatchingRule URLMatchingStrategy = "urlPattern"
24+
URLPathTemplateRule URLMatchingStrategy = "urlPathTemplate"
2325
)
2426

2527
// Type of less strict matching flags.

request.go

+15-1
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ type Request struct {
1313
scheme *string
1414
headers map[string]MatcherInterface
1515
queryParams map[string]MatcherInterface
16+
pathParams map[string]MatcherInterface
1617
cookies map[string]BasicParamMatcher
17-
bodyPatterns []BasicParamMatcher
1818
formParameters map[string]BasicParamMatcher
19+
bodyPatterns []BasicParamMatcher
1920
multipartPatterns []MultipartPatternInterface
2021
basicAuthCredentials *struct {
2122
username string
@@ -104,6 +105,16 @@ func (r *Request) WithQueryParam(param string, matcher MatcherInterface) *Reques
104105
return r
105106
}
106107

108+
// WithPathParam add param to path param list
109+
func (r *Request) WithPathParam(param string, matcher MatcherInterface) *Request {
110+
if r.pathParams == nil {
111+
r.pathParams = map[string]MatcherInterface{}
112+
}
113+
114+
r.pathParams[param] = matcher
115+
return r
116+
}
117+
107118
// WithHeader add header to header list
108119
func (r *Request) WithHeader(header string, matcher MatcherInterface) *Request {
109120
if r.headers == nil {
@@ -161,6 +172,9 @@ func (r *Request) MarshalJSON() ([]byte, error) {
161172
if len(r.queryParams) > 0 {
162173
request["queryParameters"] = r.queryParams
163174
}
175+
if len(r.pathParams) > 0 {
176+
request["pathParameters"] = r.pathParams
177+
}
164178

165179
if r.basicAuthCredentials != nil {
166180
request["basicAuthCredentials"] = map[string]string{

response.go

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ func NewResponse() Response {
3636
}
3737
}
3838

39+
func OK() Response {
40+
return NewResponse().WithStatus(http.StatusOK)
41+
}
42+
3943
// WithLogNormalRandomDelay sets log normal random delay for response
4044
func (r Response) WithLogNormalRandomDelay(median time.Duration, sigma float64) Response {
4145
r.delayDistribution = NewLogNormalRandomDelay(median, sigma)

string_value_matcher.go

+22
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,28 @@ func StartsWith(prefix string) BasicParamMatcher {
160160
return NewStringValueMatcher(ParamMatches, regex)
161161
}
162162

163+
type JSONSchemaMatcher struct {
164+
StringValueMatcher
165+
schemaVersion string
166+
}
167+
168+
// MatchesJsonSchema returns a matcher that matches when the parameter matches the specified JSON schema.
169+
// Required wiremock version >= 3.0.0
170+
func MatchesJsonSchema(schema string, schemaVersion string) BasicParamMatcher {
171+
return JSONSchemaMatcher{
172+
StringValueMatcher: NewStringValueMatcher(ParamMatchesJsonSchema, schema),
173+
schemaVersion: schemaVersion,
174+
}
175+
}
176+
177+
// MarshalJSON returns the JSON encoding of the matcher.
178+
func (m JSONSchemaMatcher) MarshalJSON() ([]byte, error) {
179+
return json.Marshal(map[string]string{
180+
string(m.strategy): m.value,
181+
"schemaVersion": m.schemaVersion,
182+
})
183+
}
184+
163185
func regexContainsStartAnchor(regex string) bool {
164186
return len(regex) > 0 && regex[0] == '^'
165187
}

stub_rule.go

+6
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ func (s *StubRule) WithQueryParam(param string, matcher MatcherInterface) *StubR
4545
return s
4646
}
4747

48+
// WithPathParam adds path param and returns *StubRule
49+
func (s *StubRule) WithPathParam(param string, matcher MatcherInterface) *StubRule {
50+
s.request.WithPathParam(param, matcher)
51+
return s
52+
}
53+
4854
// WithPort adds port and returns *StubRule
4955
func (s *StubRule) WithPort(port int64) *StubRule {
5056
s.request.WithPort(port)

testdata/matches-Json-schema.json

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"uuid": "%s",
3+
"id": "%s",
4+
"request": {
5+
"method": "POST",
6+
"urlPath": "/example",
7+
"queryParameters": {
8+
"firstName": {
9+
"matchesJsonSchema" : "{\n \"type\": \"object\",\n \"required\": [\n \"name\"\n ],\n \"properties\": {\n \"name\": {\n \"type\": \"string\"\n },\n \"tag\": {\n \"type\": \"string\"\n }\n }\n}",
10+
"schemaVersion" : "V202012"
11+
}
12+
}
13+
},
14+
"response": {
15+
"status": 200
16+
}
17+
}

testdata/not-logical-expression.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"uuid": "%s",
3+
"id": "%s",
4+
"request": {
5+
"method": "POST",
6+
"urlPath": "/example",
7+
"queryParameters": {
8+
"firstName": {
9+
"not": {
10+
"or": [
11+
{
12+
"equalTo": "John"
13+
},
14+
{
15+
"equalTo": "Jack"
16+
}
17+
]
18+
}
19+
}
20+
}
21+
},
22+
"response": {
23+
"status": 200
24+
}
25+
}

testdata/url-path-templating.json

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"uuid": "%s",
3+
"id": "%s",
4+
"request" : {
5+
"urlPathTemplate" : "/contacts/{contactId}/addresses/{addressId}",
6+
"method" : "GET",
7+
"pathParameters" : {
8+
"contactId" : {
9+
"equalTo" : "12345"
10+
},
11+
"addressId" : {
12+
"equalTo" : "99876"
13+
}
14+
}
15+
},
16+
"response" : {
17+
"status" : 200
18+
}
19+
}

url_matcher.go

+11
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,14 @@ func URLMatching(url string) URLMatcher {
5353
value: url,
5454
}
5555
}
56+
57+
// URLPathTemplate URL paths can be matched using URI templates, conforming to the same subset of the URI template standard as used in OpenAPI.
58+
// Path variable matchers can also be used in the same manner as query and form parameters.
59+
// Required wiremock >= 3.0.0
60+
// Example: /contacts/{contactId}/addresses/{addressId}
61+
func URLPathTemplate(url string) URLMatcher {
62+
return URLMatcher{
63+
strategy: URLPathTemplateRule,
64+
value: url,
65+
}
66+
}

0 commit comments

Comments
 (0)