forked from jenkins-zh/jenkins-client
/
requestmatcher.go
108 lines (88 loc) · 2.5 KB
/
requestmatcher.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package client
import (
"fmt"
"io/ioutil"
"net/http"
"reflect"
"strings"
)
// RequestMatcher to match the http request
type RequestMatcher struct {
request *http.Request
target *http.Request
verbose bool
matchOptions matchOptions
}
type matchOptions struct {
withQuery bool
withBody bool
}
// NewRequestMatcher create a request matcher will match request method and request path
func NewRequestMatcher(request *http.Request) *RequestMatcher {
return &RequestMatcher{request: request}
}
// NewVerboseRequestMatcher create a verbose request matcher will match request method and request path
func NewVerboseRequestMatcher(request *http.Request) *RequestMatcher {
return &RequestMatcher{request: request, verbose: true}
}
// WithQuery returns a matcher with query
func (request *RequestMatcher) WithQuery() *RequestMatcher {
request.matchOptions.withQuery = true
return request
}
// WithBody returns a matcher with body
func (request *RequestMatcher) WithBody() *RequestMatcher {
request.matchOptions.withBody = true
return request
}
// Matches returns a matcher with given function
func (request *RequestMatcher) Matches(x interface{}) bool {
target := x.(*http.Request)
request.target = target
match := request.request.Method == target.Method && (request.request.URL.Path == target.URL.Path ||
request.request.URL.Path == target.URL.Opaque)
if match {
match = matchHeader(request.request.Header, request.target.Header)
}
if request.matchOptions.withQuery && match {
match = request.request.URL.RawQuery == target.URL.RawQuery
}
if request.matchOptions.withBody && match {
reqBody, _ := getStrFromReader(request.request)
targetBody, _ := getStrFromReader(target)
match = reqBody == targetBody
}
return match
}
func matchHeader(left, right http.Header) bool {
if len(left) != len(right) {
return false
}
for k, v := range left {
if k == "Content-Type" { // it's hard to compare file upload cases
continue
}
if tv, ok := right[k]; !ok || !reflect.DeepEqual(v, tv) {
return false
}
}
return true
}
func getStrFromReader(request *http.Request) (text string, err error) {
reader := request.Body
if reader == nil {
return
}
if data, err := ioutil.ReadAll(reader); err == nil {
text = string(data)
// it could be read twice
payload := strings.NewReader(text)
request.Body = ioutil.NopCloser(payload)
}
return
}
// String returns the text of current object
func (request *RequestMatcher) String() string {
target := request.target
return fmt.Sprintf("%v", target)
}