From 089e8bbbe3a526ad15d79c1cd3facd04ff80f632 Mon Sep 17 00:00:00 2001 From: Ruslan Isamukhametov Date: Tue, 1 Aug 2023 11:05:02 +0300 Subject: [PATCH] Add multiple values matchers and logical matchers (#14) --- README.md | 2 +- client_test.go | 12 ++- doc.go | 5 +- expected-template.json | 35 ++++++++- logical_matcher.go | 54 +++++++++++++ matching.go | 168 ++-------------------------------------- multi_value_matcher.go | 33 ++++++++ multipart_pattern.go | 36 ++------- request.go | 104 ++++++++++++------------- string_value_matcher.go | 108 ++++++++++++++++++++++++++ stub_rule.go | 37 ++++++--- url_matcher.go | 49 ++++++++++++ 12 files changed, 381 insertions(+), 262 deletions(-) create mode 100644 logical_matcher.go create mode 100644 multi_value_matcher.go create mode 100644 string_value_matcher.go create mode 100644 url_matcher.go diff --git a/README.md b/README.md index 0e9c48d..f297163 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ func TestSome(t *testing.T) { // stubbing POST http://0.0.0.0:8080/example wiremockClient.StubFor(wiremock.Post(wiremock.URLPathEqualTo("/example")). - WithQueryParam("firstName", wiremock.EqualTo("Jhon")). + WithQueryParam("firstName", wiremock.EqualTo("John")). WithQueryParam("lastName", wiremock.NotMatching("Black")). WithBodyPattern(wiremock.EqualToJson(`{"meta": "information"}`)). WithHeader("x-session", wiremock.Matching("^\\S+fingerprint\\S+$")). diff --git a/client_test.go b/client_test.go index 24f54f1..0331c79 100644 --- a/client_test.go +++ b/client_test.go @@ -22,9 +22,14 @@ func TestStubRule_ToJson(t *testing.T) { } postStubRule := Post(URLPathEqualTo("/example")). - WithQueryParam("firstName", EqualTo("Jhon")). + WithHost(EqualTo("localhost")). + WithScheme("http"). + WithPort(8080). + WithQueryParam("firstName", EqualTo("John").Or(EqualTo("Jack"))). WithQueryParam("lastName", NotMatching("Black")). - WithQueryParam("nickname", EqualToIgnoreCase("jhonBlack")). + WithQueryParam("nickname", EqualToIgnoreCase("johnBlack")). + WithQueryParam("address", Includes(EqualTo("1"), Contains("2"), NotContains("3"))). + WithQueryParam("id", Contains("1").And(NotContains("2"))). WithBodyPattern(EqualToJson(`{"meta": "information"}`, IgnoreArrayOrder, IgnoreExtraElements)). WithBodyPattern(Contains("information")). WithMultipartPattern( @@ -53,15 +58,18 @@ func TestStubRule_ToJson(t *testing.T) { if err != nil { t.Fatalf("failed to read expected-template.json %v", err) } + rawResult, err := json.Marshal(postStubRule) if err != nil { t.Fatalf("StubRole json.Marshal error: %v", err) } + var expected map[string]interface{} err = json.Unmarshal([]byte(fmt.Sprintf(string(rawExpectedRequestBody), postStubRule.uuid, postStubRule.uuid)), &expected) if err != nil { t.Fatalf("StubRole json.Unmarshal error: %v", err) } + var parsedResult map[string]interface{} err = json.Unmarshal(rawResult, &parsedResult) if err != nil { diff --git a/doc.go b/doc.go index 71c2f55..4d39fd5 100644 --- a/doc.go +++ b/doc.go @@ -8,7 +8,7 @@ Some might consider it a service virtualization tool or a mock server. HTTP request: - POST /example?firstName=Jhon&lastName=Any string other than "Gray" HTTP/1.1 + POST /example?firstName=John&lastName=Any string other than "Gray" HTTP/1.1 Host: 0.0.0.0:8080 x-session: somefingerprintsome Content-Type: application/json @@ -26,7 +26,7 @@ Stub: client := wiremock.NewClient("http://0.0.0.0:8080") client.StubFor(wiremock.Post(wiremock.URLPathEqualTo("/example")). - WithQueryParam("firstName", wiremock.EqualTo("Jhon")). + WithQueryParam("firstName", wiremock.EqualTo("John")). WithQueryParam("lastName", wiremock.NotMatching("Gray")). WithBodyPattern(wiremock.EqualToJson(`{"meta": "information"}`)). WithHeader("x-session", wiremock.Matching("^\\S+fingerprint\\S+$")). @@ -61,6 +61,5 @@ You can verify if a request has been made that matches the mapping. client.StubFor(exampleStubRule) // ... client.Verify(exampleStubRule.Request(), 1) - */ package wiremock diff --git a/expected-template.json b/expected-template.json index 4042ba4..d60dbc7 100644 --- a/expected-template.json +++ b/expected-template.json @@ -7,6 +7,11 @@ "newScenarioState": "Stopped", "request": { "method": "POST", + "scheme": "http", + "host": { + "equalTo": "localhost" + }, + "port": 8080, "basicAuthCredentials": { "password": "password", "username": "username" @@ -58,14 +63,40 @@ }, "queryParameters": { "firstName": { - "equalTo": "Jhon" + "or": [ + { + "equalTo": "John" + }, + { + "equalTo": "Jack" + } + ] }, "lastName": { "doesNotMatch": "Black" }, "nickname": { - "equalTo": "jhonBlack", + "equalTo": "johnBlack", "caseInsensitive": true + }, + "address": { + "includes" : [ + { + "equalTo": "1" + }, + { + "contains": "2" + }, + { + "doesNotContain": "3" + } + ] + }, + "id": { + "and": [ + {"contains": "1"}, + {"doesNotContain": "2"} + ] } }, "urlPath": "/example" diff --git a/logical_matcher.go b/logical_matcher.go new file mode 100644 index 0000000..973081d --- /dev/null +++ b/logical_matcher.go @@ -0,0 +1,54 @@ +package wiremock + +import ( + "encoding/json" +) + +type LogicalMatcher struct { + operator string + operands []BasicParamMatcher +} + +func (m LogicalMatcher) MarshalJSON() ([]byte, error) { + jsonMap := map[string]interface{}{ + m.operator: m.operands, + } + + return json.Marshal(jsonMap) +} + +// Or returns a logical OR of the current matcher and the given matcher. +func (m LogicalMatcher) Or(matcher BasicParamMatcher) BasicParamMatcher { + if m.operator == "or" { + m.operands = append(m.operands, matcher) + return m + } + + return Or(m, matcher) +} + +// And returns a logical AND of the current matcher and the given matcher. +func (m LogicalMatcher) And(matcher BasicParamMatcher) BasicParamMatcher { + if m.operator == "and" { + m.operands = append(m.operands, matcher) + return m + } + + return And(m, matcher) +} + +// Or returns a logical OR of the list of matchers. +func Or(matchers ...BasicParamMatcher) LogicalMatcher { + return LogicalMatcher{ + operator: "or", + operands: matchers, + } +} + +// And returns a logical AND of the list of matchers. +func And(matchers ...BasicParamMatcher) LogicalMatcher { + return LogicalMatcher{ + operator: "and", + operands: matchers, + } +} diff --git a/matching.go b/matching.go index 8f2153b..303be48 100644 --- a/matching.go +++ b/matching.go @@ -11,6 +11,7 @@ const ( ParamMatchesJsonPath ParamMatchingStrategy = "matchesJsonPath" ParamAbsent ParamMatchingStrategy = "absent" ParamDoesNotMatch ParamMatchingStrategy = "doesNotMatch" + ParamDoesNotContains ParamMatchingStrategy = "doesNotContain" ) // Types of url matching. @@ -27,6 +28,11 @@ const ( IgnoreExtraElements EqualFlag = "ignoreExtraElements" ) +const ( + ParamHasExactly MultiValueMatchingStrategy = "hasExactly" + ParamIncludes MultiValueMatchingStrategy = "includes" +) + // EqualFlag is enum of less strict matching flag. type EqualFlag string @@ -36,163 +42,5 @@ type URLMatchingStrategy string // ParamMatchingStrategy is enum params matching type. type ParamMatchingStrategy string -// URLMatcher is structure for defining the type of url matching. -type URLMatcher struct { - strategy URLMatchingStrategy - value string -} - -// Strategy returns URLMatchingStrategy of URLMatcher. -func (m URLMatcher) Strategy() URLMatchingStrategy { - return m.strategy -} - -// Value returns value of URLMatcher. -func (m URLMatcher) Value() string { - return m.value -} - -// URLEqualTo returns URLMatcher with URLEqualToRule matching strategy. -func URLEqualTo(url string) URLMatcher { - return URLMatcher{ - strategy: URLEqualToRule, - value: url, - } -} - -// URLPathEqualTo returns URLMatcher with URLPathEqualToRule matching strategy. -func URLPathEqualTo(url string) URLMatcher { - return URLMatcher{ - strategy: URLPathEqualToRule, - value: url, - } -} - -// URLPathMatching returns URLMatcher with URLPathMatchingRule matching strategy. -func URLPathMatching(url string) URLMatcher { - return URLMatcher{ - strategy: URLPathMatchingRule, - value: url, - } -} - -// URLMatching returns URLMatcher with URLMatchingRule matching strategy. -func URLMatching(url string) URLMatcher { - return URLMatcher{ - strategy: URLMatchingRule, - value: url, - } -} - -// ParamMatcher is structure for defining the type of params. -type ParamMatcher struct { - strategy ParamMatchingStrategy - value string - flags map[string]bool -} - -// Strategy returns ParamMatchingStrategy of ParamMatcher. -func (m ParamMatcher) Strategy() ParamMatchingStrategy { - return m.strategy -} - -// Value returns value of ParamMatcher. -func (m ParamMatcher) Value() string { - return m.value -} - -// Flags return value of ParamMatcher. -func (m ParamMatcher) Flags() map[string]bool { - return m.flags -} - -// EqualTo returns ParamMatcher with ParamEqualTo matching strategy. -func EqualTo(param string) ParamMatcher { - return ParamMatcher{ - strategy: ParamEqualTo, - value: param, - } -} - -// EqualToIgnoreCase returns ParamMatcher with ParamEqualToIgnoreCase matching strategy -func EqualToIgnoreCase(param string) ParamMatcher { - return ParamMatcher{ - strategy: ParamEqualTo, - value: param, - flags: map[string]bool{ - "caseInsensitive": true, - }, - } -} - -// Matching returns ParamMatcher with ParamMatches matching strategy. -func Matching(param string) ParamMatcher { - return ParamMatcher{ - strategy: ParamMatches, - value: param, - } -} - -// Contains returns ParamMatcher with ParamContains matching strategy. -func Contains(param string) ParamMatcher { - return ParamMatcher{ - strategy: ParamContains, - value: param, - } -} - -// EqualToXml returns ParamMatcher with ParamEqualToXml matching strategy. -func EqualToXml(param string) ParamMatcher { - return ParamMatcher{ - strategy: ParamEqualToXml, - value: param, - } -} - -// EqualToJson returns ParamMatcher with ParamEqualToJson matching strategy. -func EqualToJson(param string, flags ...EqualFlag) ParamMatcher { - mflags := make(map[string]bool, len(flags)) - for _, flag := range flags { - mflags[string(flag)] = true - } - - return ParamMatcher{ - strategy: ParamEqualToJson, - value: param, - flags: mflags, - } -} - -// MatchingXPath returns ParamMatcher with ParamMatchesXPath matching strategy. -func MatchingXPath(param string) ParamMatcher { - return ParamMatcher{ - strategy: ParamMatchesXPath, - value: param, - } -} - -// MatchingJsonPath returns ParamMatcher with ParamMatchesJsonPath matching strategy. -func MatchingJsonPath(param string) ParamMatcher { - return ParamMatcher{ - strategy: ParamMatchesJsonPath, - value: param, - } -} - -// NotMatching returns ParamMatcher with ParamDoesNotMatch matching strategy. -func NotMatching(param string) ParamMatcher { - return ParamMatcher{ - strategy: ParamDoesNotMatch, - value: param, - } -} - -func Absent() ParamMatcher { - return ParamMatcher{ - strategy: ParamAbsent, - value: "", - flags: map[string]bool{ - string(ParamAbsent): true, - }, - } -} +// MultiValueMatchingStrategy is enum multi value matching type. +type MultiValueMatchingStrategy string diff --git a/multi_value_matcher.go b/multi_value_matcher.go new file mode 100644 index 0000000..dc380ff --- /dev/null +++ b/multi_value_matcher.go @@ -0,0 +1,33 @@ +package wiremock + +import "encoding/json" + +type MultiValueMatcher struct { + strategy MultiValueMatchingStrategy + matchers []BasicParamMatcher +} + +// MarshalJSON returns the JSON encoding of the matcher. +func (m MultiValueMatcher) MarshalJSON() ([]byte, error) { + jsonMap := map[string]interface{}{ + string(m.strategy): m.matchers, + } + + return json.Marshal(jsonMap) +} + +// HasExactly returns a matcher that matches when the parameter has exactly the specified values. +func HasExactly(matchers ...BasicParamMatcher) MultiValueMatcher { + return MultiValueMatcher{ + strategy: ParamHasExactly, + matchers: matchers, + } +} + +// Includes returns a matcher that matches when the parameter includes the specified values. +func Includes(matchers ...BasicParamMatcher) MultiValueMatcher { + return MultiValueMatcher{ + strategy: ParamIncludes, + matchers: matchers, + } +} diff --git a/multipart_pattern.go b/multipart_pattern.go index 48a640b..8755b41 100644 --- a/multipart_pattern.go +++ b/multipart_pattern.go @@ -14,8 +14,8 @@ type MultipartMatchingType string type MultipartPattern struct { matchingType MultipartMatchingType - headers map[string]ParamMatcherInterface - bodyPatterns []ParamMatcher + headers map[string]json.Marshaler + bodyPatterns []BasicParamMatcher } func NewMultipartPattern() *MultipartPattern { @@ -26,7 +26,7 @@ func NewMultipartPattern() *MultipartPattern { func (m *MultipartPattern) WithName(name string) *MultipartPattern { if m.headers == nil { - m.headers = map[string]ParamMatcherInterface{} + m.headers = map[string]json.Marshaler{} } m.headers["Content-Disposition"] = Contains(fmt.Sprintf(`name="%s"`, name)) @@ -48,14 +48,14 @@ func (m *MultipartPattern) WithAnyMatchingType() *MultipartPattern { return m } -func (m *MultipartPattern) WithBodyPattern(matcher ParamMatcher) *MultipartPattern { +func (m *MultipartPattern) WithBodyPattern(matcher BasicParamMatcher) *MultipartPattern { m.bodyPatterns = append(m.bodyPatterns, matcher) return m } -func (m *MultipartPattern) WithHeader(header string, matcher ParamMatcherInterface) *MultipartPattern { +func (m *MultipartPattern) WithHeader(header string, matcher json.Marshaler) *MultipartPattern { if m.headers == nil { - m.headers = map[string]ParamMatcherInterface{} + m.headers = map[string]json.Marshaler{} } m.headers[header] = matcher @@ -69,31 +69,11 @@ func (m *MultipartPattern) MarshalJSON() ([]byte, error) { } if len(m.bodyPatterns) > 0 { - bodyPatterns := make([]map[string]interface{}, len(m.bodyPatterns)) - for i, bodyPattern := range m.bodyPatterns { - bodyPatterns[i] = map[string]interface{}{ - string(bodyPattern.Strategy()): bodyPattern.Value(), - } - - for flag, value := range bodyPattern.flags { - bodyPatterns[i][flag] = value - } - } - multipart["bodyPatterns"] = bodyPatterns + multipart["bodyPatterns"] = m.bodyPatterns } if len(m.headers) > 0 { - headers := make(map[string]map[string]interface{}, len(m.headers)) - for key, header := range m.headers { - headers[key] = map[string]interface{}{ - string(header.Strategy()): header.Value(), - } - - for flag, value := range header.Flags() { - headers[key][flag] = value - } - } - multipart["headers"] = headers + multipart["headers"] = m.headers } return json.Marshal(multipart) diff --git a/request.go b/request.go index f624355..bef1ef6 100644 --- a/request.go +++ b/request.go @@ -8,10 +8,13 @@ import ( type Request struct { urlMatcher URLMatcherInterface method string - headers map[string]ParamMatcherInterface - queryParams map[string]ParamMatcherInterface - cookies map[string]ParamMatcherInterface - bodyPatterns []ParamMatcher + host BasicParamMatcher + port *int64 + scheme *string + headers map[string]json.Marshaler + queryParams map[string]json.Marshaler + cookies map[string]BasicParamMatcher + bodyPatterns []BasicParamMatcher multipartPatterns []*MultipartPattern basicAuthCredentials *struct { username string @@ -27,6 +30,24 @@ func NewRequest(method string, urlMatcher URLMatcherInterface) *Request { } } +// WithPort is fluent-setter for port +func (r *Request) WithPort(port int64) *Request { + r.port = &port + return r +} + +// WithScheme is fluent-setter for scheme +func (r *Request) WithScheme(scheme string) *Request { + r.scheme = &scheme + return r +} + +// WithHost is fluent-setter for host +func (r *Request) WithHost(host BasicParamMatcher) *Request { + r.host = host + return r +} + // WithMethod is fluent-setter for http verb func (r *Request) WithMethod(method string) *Request { r.method = method @@ -40,7 +61,7 @@ func (r *Request) WithURLMatched(urlMatcher URLMatcherInterface) *Request { } // WithBodyPattern adds body pattern to list -func (r *Request) WithBodyPattern(matcher ParamMatcher) *Request { +func (r *Request) WithBodyPattern(matcher BasicParamMatcher) *Request { r.bodyPatterns = append(r.bodyPatterns, matcher) return r } @@ -64,9 +85,9 @@ func (r *Request) WithBasicAuth(username, password string) *Request { } // WithQueryParam add param to query param list -func (r *Request) WithQueryParam(param string, matcher ParamMatcherInterface) *Request { +func (r *Request) WithQueryParam(param string, matcher json.Marshaler) *Request { if r.queryParams == nil { - r.queryParams = map[string]ParamMatcherInterface{} + r.queryParams = map[string]json.Marshaler{} } r.queryParams[param] = matcher @@ -74,9 +95,9 @@ func (r *Request) WithQueryParam(param string, matcher ParamMatcherInterface) *R } // WithHeader add header to header list -func (r *Request) WithHeader(header string, matcher ParamMatcherInterface) *Request { +func (r *Request) WithHeader(header string, matcher json.Marshaler) *Request { if r.headers == nil { - r.headers = map[string]ParamMatcherInterface{} + r.headers = map[string]json.Marshaler{} } r.headers[header] = matcher @@ -84,9 +105,9 @@ func (r *Request) WithHeader(header string, matcher ParamMatcherInterface) *Requ } // WithCookie is fluent-setter for cookie -func (r *Request) WithCookie(cookie string, matcher ParamMatcherInterface) *Request { +func (r *Request) WithCookie(cookie string, matcher BasicParamMatcher) *Request { if r.cookies == nil { - r.cookies = map[string]ParamMatcherInterface{} + r.cookies = map[string]BasicParamMatcher{} } r.cookies[cookie] = matcher @@ -99,60 +120,33 @@ func (r *Request) MarshalJSON() ([]byte, error) { "method": r.method, string(r.urlMatcher.Strategy()): r.urlMatcher.Value(), } + + if r.scheme != nil { + request["scheme"] = r.scheme + } + + if r.host != nil { + request["host"] = r.host + } + + if r.port != nil { + request["port"] = r.port + } + if len(r.bodyPatterns) > 0 { - bodyPatterns := make([]map[string]interface{}, len(r.bodyPatterns)) - for i, bodyPattern := range r.bodyPatterns { - bodyPatterns[i] = map[string]interface{}{ - string(bodyPattern.Strategy()): bodyPattern.Value(), - } - - for flag, value := range bodyPattern.flags { - bodyPatterns[i][flag] = value - } - } - request["bodyPatterns"] = bodyPatterns + request["bodyPatterns"] = r.bodyPatterns } if len(r.multipartPatterns) > 0 { request["multipartPatterns"] = r.multipartPatterns } if len(r.headers) > 0 { - headers := make(map[string]map[string]interface{}, len(r.headers)) - for key, header := range r.headers { - headers[key] = map[string]interface{}{ - string(header.Strategy()): header.Value(), - } - - for flag, value := range header.Flags() { - headers[key][flag] = value - } - } - request["headers"] = headers + request["headers"] = r.headers } if len(r.cookies) > 0 { - cookies := make(map[string]map[string]interface{}, len(r.cookies)) - for key, cookie := range r.cookies { - cookies[key] = map[string]interface{}{ - string(cookie.Strategy()): cookie.Value(), - } - - for flag, value := range cookie.Flags() { - cookies[key][flag] = value - } - } - request["cookies"] = cookies + request["cookies"] = r.cookies } if len(r.queryParams) > 0 { - params := make(map[string]map[string]interface{}, len(r.queryParams)) - for key, param := range r.queryParams { - params[key] = map[string]interface{}{ - string(param.Strategy()): param.Value(), - } - - for flag, value := range param.Flags() { - params[key][flag] = value - } - } - request["queryParameters"] = params + request["queryParameters"] = r.queryParams } if r.basicAuthCredentials != nil { diff --git a/string_value_matcher.go b/string_value_matcher.go new file mode 100644 index 0000000..1f9a95a --- /dev/null +++ b/string_value_matcher.go @@ -0,0 +1,108 @@ +package wiremock + +import "encoding/json" + +type BasicParamMatcher interface { + json.Marshaler + Or(stringMatcher BasicParamMatcher) BasicParamMatcher + And(stringMatcher BasicParamMatcher) BasicParamMatcher +} + +type StringValueMatcher struct { + strategy ParamMatchingStrategy + value string + flags []string +} + +func (m StringValueMatcher) MarshalJSON() ([]byte, error) { + jsonMap := make(map[string]interface{}, 1+len(m.flags)) + if m.strategy != "" { + jsonMap[string(m.strategy)] = m.value + } + for _, flag := range m.flags { + jsonMap[flag] = true + } + + return json.Marshal(jsonMap) +} + +// Or returns a logical OR of the two matchers. +func (m StringValueMatcher) Or(matcher BasicParamMatcher) BasicParamMatcher { + return Or(m, matcher) +} + +// And returns a logical AND of the two matchers. +func (m StringValueMatcher) And(matcher BasicParamMatcher) BasicParamMatcher { + return And(m, matcher) +} + +// NewStringValueMatcher creates a new StringValueMatcher. +func NewStringValueMatcher(strategy ParamMatchingStrategy, value string, flags ...string) StringValueMatcher { + return StringValueMatcher{ + strategy: strategy, + value: value, + flags: flags, + } +} + +// EqualTo returns a matcher that matches when the parameter equals the specified value. +func EqualTo(value string) BasicParamMatcher { + return NewStringValueMatcher(ParamEqualTo, value) +} + +// EqualToIgnoreCase returns a matcher that matches when the parameter equals the specified value, ignoring case. +func EqualToIgnoreCase(value string) BasicParamMatcher { + return NewStringValueMatcher(ParamEqualTo, value, "caseInsensitive") +} + +// Matching returns a matcher that matches when the parameter matches the specified regular expression. +func Matching(param string) BasicParamMatcher { + return NewStringValueMatcher(ParamMatches, param) +} + +// EqualToXml returns a matcher that matches when the parameter is equal to the specified XML. +func EqualToXml(param string) BasicParamMatcher { + return NewStringValueMatcher(ParamEqualToXml, param) +} + +// EqualToJson returns a matcher that matches when the parameter is equal to the specified JSON. +func EqualToJson(param string, equalJsonFlags ...EqualFlag) BasicParamMatcher { + flags := make([]string, len(equalJsonFlags)) + for i, flag := range equalJsonFlags { + flags[i] = string(flag) + } + + return NewStringValueMatcher(ParamEqualToJson, param, flags...) +} + +// MatchingXPath returns a matcher that matches when the parameter matches the specified XPath. +func MatchingXPath(param string) BasicParamMatcher { + return NewStringValueMatcher(ParamMatchesXPath, param) +} + +// MatchingJsonPath returns a matcher that matches when the parameter matches the specified JSON path. +func MatchingJsonPath(param string) BasicParamMatcher { + return NewStringValueMatcher(ParamMatchesJsonPath, param) +} + +// NotMatching returns a matcher that matches when the parameter does not match the specified regular expression. +func NotMatching(param string) BasicParamMatcher { + return NewStringValueMatcher(ParamDoesNotMatch, param) +} + +// Absent returns a matcher that matches when the parameter is absent. +func Absent() BasicParamMatcher { + return StringValueMatcher{ + flags: []string{string(ParamAbsent)}, + } +} + +// Contains returns a matcher that matches when the parameter contains the specified value. +func Contains(param string) BasicParamMatcher { + return NewStringValueMatcher(ParamContains, param) +} + +// NotContains returns a matcher that matches when the parameter does not contain the specified value. +func NotContains(param string) BasicParamMatcher { + return NewStringValueMatcher(ParamDoesNotContains, param) +} diff --git a/stub_rule.go b/stub_rule.go index 1068e7d..669bd8a 100644 --- a/stub_rule.go +++ b/stub_rule.go @@ -11,13 +11,6 @@ import ( const ScenarioStateStarted = "Started" -// ParamMatcherInterface is pair ParamMatchingStrategy and string matched value -type ParamMatcherInterface interface { - Strategy() ParamMatchingStrategy - Value() string - Flags() map[string]bool -} - // URLMatcherInterface is pair URLMatchingStrategy and string matched value type URLMatcherInterface interface { Strategy() URLMatchingStrategy @@ -34,6 +27,10 @@ type response struct { fixedDelayMilliseconds time.Duration } +type Matcher interface { + StringValueMatcher | MultiValueMatcher +} + // StubRule is struct of http Request body to WireMock type StubRule struct { uuid string @@ -63,25 +60,43 @@ func (s *StubRule) Request() *Request { } // WithQueryParam adds query param and returns *StubRule -func (s *StubRule) WithQueryParam(param string, matcher ParamMatcherInterface) *StubRule { +func (s *StubRule) WithQueryParam(param string, matcher json.Marshaler) *StubRule { s.request.WithQueryParam(param, matcher) return s } +// WithPort adds port and returns *StubRule +func (s *StubRule) WithPort(port int64) *StubRule { + s.request.WithPort(port) + return s +} + +// WithScheme adds scheme and returns *StubRule +func (s *StubRule) WithScheme(scheme string) *StubRule { + s.request.WithScheme(scheme) + return s +} + +// WithHost adds host and returns *StubRule +func (s *StubRule) WithHost(host BasicParamMatcher) *StubRule { + s.request.WithHost(host) + return s +} + // WithHeader adds header to Headers and returns *StubRule -func (s *StubRule) WithHeader(header string, matcher ParamMatcherInterface) *StubRule { +func (s *StubRule) WithHeader(header string, matcher json.Marshaler) *StubRule { s.request.WithHeader(header, matcher) return s } // WithCookie adds cookie and returns *StubRule -func (s *StubRule) WithCookie(cookie string, matcher ParamMatcherInterface) *StubRule { +func (s *StubRule) WithCookie(cookie string, matcher BasicParamMatcher) *StubRule { s.request.WithCookie(cookie, matcher) return s } // WithBodyPattern adds body pattern and returns *StubRule -func (s *StubRule) WithBodyPattern(matcher ParamMatcher) *StubRule { +func (s *StubRule) WithBodyPattern(matcher BasicParamMatcher) *StubRule { s.request.WithBodyPattern(matcher) return s } diff --git a/url_matcher.go b/url_matcher.go new file mode 100644 index 0000000..cfa75d5 --- /dev/null +++ b/url_matcher.go @@ -0,0 +1,49 @@ +package wiremock + +// URLMatcher is structure for defining the type of url matching. +type URLMatcher struct { + strategy URLMatchingStrategy + value string +} + +// Strategy returns URLMatchingStrategy of URLMatcher. +func (m URLMatcher) Strategy() URLMatchingStrategy { + return m.strategy +} + +// Value returns value of URLMatcher. +func (m URLMatcher) Value() string { + return m.value +} + +// URLEqualTo returns URLMatcher with URLEqualToRule matching strategy. +func URLEqualTo(url string) URLMatcher { + return URLMatcher{ + strategy: URLEqualToRule, + value: url, + } +} + +// URLPathEqualTo returns URLMatcher with URLPathEqualToRule matching strategy. +func URLPathEqualTo(url string) URLMatcher { + return URLMatcher{ + strategy: URLPathEqualToRule, + value: url, + } +} + +// URLPathMatching returns URLMatcher with URLPathMatchingRule matching strategy. +func URLPathMatching(url string) URLMatcher { + return URLMatcher{ + strategy: URLPathMatchingRule, + value: url, + } +} + +// URLMatching returns URLMatcher with URLMatchingRule matching strategy. +func URLMatching(url string) URLMatcher { + return URLMatcher{ + strategy: URLMatchingRule, + value: url, + } +}